Passenger、Sinatra、Nginx、RabbitMQ和SSE(Passenger如何启动进程以及Ruby线程在图片中的位置)

Passenger、Sinatra、Nginx、RabbitMQ和SSE(Passenger如何启动进程以及Ruby线程在图片中的位置),nginx,rabbitmq,sinatra,passenger,server-sent-events,Nginx,Rabbitmq,Sinatra,Passenger,Server Sent Events,我的当前设置有问题,无法按预期工作,并阻止我进一步启用启用服务器发送事件(SSE)的网站。我的主要问题可以在下面粗体显示,但可以归结为“如何在乘客设置中从Sinatra web应用程序启动额外线程?” 我使用乘客5.0.21和Sinatra 1.4.6。该应用程序是作为一个经典的Sinatra应用程序编写的,不是模块化的,但如果需要可以更改 我已将指令passenger\u min\u instances 3放入Nginx配置中,以至少启动3个web应用程序实例。我在我的Sinatra应用程序的

我的当前设置有问题,无法按预期工作,并阻止我进一步启用启用服务器发送事件(SSE)的网站。我的主要问题可以在下面粗体显示,但可以归结为“如何在乘客设置中从Sinatra web应用程序启动额外线程?”

我使用乘客5.0.21和Sinatra 1.4.6。该应用程序是作为一个经典的Sinatra应用程序编写的,不是模块化的,但如果需要可以更改

我已将指令
passenger\u min\u instances 3
放入Nginx配置中,以至少启动3个web应用程序实例。我在我的Sinatra应用程序的
config.ru
文件中有两个
put
,因此当线程启动时,我在
/var/log/nginx/passenger.log
中得到反馈,当线程通过RabbitMQ队列接收消息时:

...
Thread.new {
  puts " [* #{Thread.current.inspect}] Waiting for logs. To exit press CTRL+C"

  begin
    q.subscribe(:block => true) do |delivery_info, properties, body|
      puts " [x #{Thread.current.inspect}] #{body}"
    end
  rescue Interrupt => _
    ch.close
    conn.close
  end
}

run Sinatra::Application
我期望该代码运行n次,n是由Passenger启动的进程数。看起来情况并非如此

此外,我的
app.rb
包含了很多东西,可以简化为:

puts "(CLASS)... Inside thread #{Thread.current.inspect}"

configure do
  puts "(CONFIGURE)... Inside thread #{Thread.current.inspect}"
end

get '/debug' do
  puts "(DEBUG)... Inside thread #{Thread.current.inspect}"
end
当我重新启动Nginx并使第一个httpget访问URL
/debug
时,进程被实例化,其中一个进程为请求提供服务。在
/var/log/nginx/passenger.log
中我能得到什么

(CLASS)... Inside thread #<Thread:0x007fb29f4ca258 run>
(CONFIGURE)... Inside thread #<Thread:0x007fb29f4ca258 run>
[* #<Thread:0x007fb29f7f8038@config.ru:68 run>] Waiting for logs. To exit press CTRL+C
(DEBUG)... Inside thread #<Thread:0x007fb29f4ca8e8@/usr/lib/ruby/vendor_ruby/phusion_passenger
192.168.0.11 - test [30/Dec/2015:10:09:08 +0100] "GET /debug HTTP/1.1" 200 2184 0.0138
ruby测试程序发布RabbitMQ消息供订阅者接收,有时有效,有时无效。乘客可能会关闭正在运行的进程,即使它在给定的时间内没有看到请求。日志中没有显示任何内容。没有来自订阅者线程的反馈,也没有来自乘客本身的消息

如果我刷新页面,我会得到
DEBUG
消息和
get/DEBUG
跟踪<代码>乘客状态--verbose显示第一个进程现在已经处理了两个请求

我在不同的测试中看到,我必须发出大量请求,以使乘客与其他2个进程一起服务请求,甚至启动新进程,最多6个。让我们在同一局域网中的另一台机器上使用
root@backup:~#ab-A测试:测试-kc 1000-n 10000https://192.168.0.10:445/debug
。Passenger已启动最多6个进程来处理请求,但是
Passenger.log
文件中除了
DEBUG
消息和
GET/DEBUG
跟踪之外,我看不到任何内容,就好像没有启动其他进程一样

$ passenger-status --verbose
----------- General information -----------
Max pool size : 6
App groups    : 1
Processes     : 6
Requests in top-level queue : 0

----------- Application groups -----------
/home/hydro/web2/public:
  App root: /home/hydro/web2
  Requests in queue: 0
  * PID: 1116    Sessions: 0       Processed: 664     Uptime: 16m 29s
    CPU: 0%      Memory  : 28M     Last used: 32s ago
  * PID: 1123    Sessions: 0       Processed: 625     Uptime: 16m 29s
    CPU: 0%      Memory  : 27M     Last used: 32s ago
  * PID: 1130    Sessions: 0       Processed: 614     Uptime: 16m 29s
    CPU: 0%      Memory  : 27M     Last used: 32s ago
  * PID: 2105    Sessions: 0       Processed: 106     Uptime: 33s
    CPU: 0%      Memory  : 23M     Last used: 32s ago
  * PID: 2112    Sessions: 0       Processed: 103     Uptime: 33s
    CPU: 0%      Memory  : 22M     Last used: 32s ago
  * PID: 2119    Sessions: 0       Processed: 92      Uptime: 33s
    CPU: 0%      Memory  : 21M     Last used: 32s ago
因此,主要问题是:如何在每次进程启动时从Sinatra web应用程序进程启动(RabbitMQ订阅服务器)线程

我希望能够将数据发送到我的web应用程序进程,以便他们可以使用SSE将数据发送回web客户端。我希望每个web应用程序进程有两个线程:Sinatra使用的主线程和我的额外线程来做一些RabbitMQ的事情。还有一个Oracle数据库和一个Erlang后端,但我认为它们与此无关

我还想知道Passenger如何处理Sinatra web应用程序中的流程实例化。多Ruby环境?如果启动了多个进程,该类看起来怎么可能只实例化一次?文件
config.ru
(甚至
app.rb
)是否仅在启动多个进程时处理一次?我在网上读了很多东西,但是我想不出来

更一般地说,使用Ruby、Nginx、Passenger和Sinatra进行SSE的正确方式是什么

为清晰起见,下文提供了有关Nginx的详细信息

Nginx被配置为站在乘客前面的反向代理,web应用程序在
服务器
位置
下配置,使用SSL和HTTP基本身份验证以及以下指令:

location / {
  proxy_buffering off;
  proxy_cache off;

  proxy_pass_request_headers on;
  passenger_set_header Host $http_host;
  passenger_set_header X-Real-IP  $remote_addr;
  passenger_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  passenger_set_header X-Forwarded-Proto $scheme;
  passenger_set_header X-Remote-User $remote_user;
  passenger_set_header Host $http_host;
  passenger_min_instances 3;
  proxy_redirect off;
  passenger_enabled on;
  passenger_ruby /home/hydro/.rbenv/versions/2.3.0/bin/ruby;
  passenger_load_shell_envvars on;
  passenger_nodejs /usr/bin/nodejs;
  passenger_friendly_error_pages on;
}

我认为你目前的架构是错误的。您的Sinatra应用程序不应该与额外的线程混合使用,也不应该仅仅为了向您的客户端发送推送而保持活动状态——您应该有一个单独的推送服务器,专门用于推送消息,并让您的HTTP API做它最擅长的事情——直到收到请求为止

您提到您正在使用nginx,因此我建议您在本模块中进行编译:

现在,您可以摆脱RabbitMQ队列—任何需要将消息推送到推送订阅者之一的进程只需向该模块的RESTful API发送HTTP请求:

示例curl请求:

curl -s -v -X POST 'http://localhost/pub?id=my_channel_1' -d 'Hello World!'

当然,默认情况下,出于安全原因,此模块将只侦听本地主机的请求。

我认为您是对的。我对建筑的选择是错误的。我喜欢使用HTTP的独立推送服务器的想法。它很容易与Erlang或Oracle数据库一起使用
curl -s -v -X POST 'http://localhost/pub?id=my_channel_1' -d 'Hello World!'