当我在Unicorn服务器上运行时,Websockets在我的Rails应用程序中不起作用,但在瘦服务器上运行

Bea*_*red 7 javascript ruby-on-rails heroku websocket

我正在学习Ruby on Rails,在Heroku上使用WebSockets构建一个实时Web应用程序,但我无法弄清楚为什么在Unicorn服务器上运行时websocket连接失败.我将我的Rails应用程序配置为使用Procfile在本地和Heroku上运行Unicorn ...

web: bundle exec unicorn -p $PORT -c ./config/unicorn.rb
Run Code Online (Sandbox Code Playgroud)

...我从当地开始$foreman start.在javascript中在客户端上创建websocket连接时发生故障...

var dispatcher = new WebSocketRails('0.0.0.0:3000/websocket'); //I update the URL before pushing to Heroku
Run Code Online (Sandbox Code Playgroud)

...在Chrome Javascript控制台中出现以下错误, 'websocket connection to ws://0.0.0.0:3000/websocket' failed. Connection closed before receiving a handshake response.

...当我在Heroku上的Unicorn上运行它时,我在Chrome Javascript控制台中收到了类似的错误, 'websocket connection to ws://myapp.herokuapp.com/websocket' failed. Error during websocket handshake. Unexpected response code: 500.

Heroku日志中的堆栈跟踪说, RuntimeError (eventmachine not initialized: evma_install_oneshot_timer):

奇怪的是,当我使用该命令在Thin服务器上本地运行它时,它工作正常$rails s.

我花了最近五个小时在线研究这个问题并没有找到解决方案.任何解决这个问题的想法,甚至是从我的工具中获取更多信息的想法,都将不胜感激!

XA2*_*21X 24

更新:我觉得很奇怪,WebSocket的护栏,而仅支持基于EventMachine的的Web服务器王菲-的WebSocketWebSocket的护栏是基于,支持许多多线程功能的Web服务器.

经过进一步的调查和测试,我意识到我之前的假设是错误的.websocket-rails似乎不需要基于EventMachine的Web服务器,而是需要支持多线程(因此没有Unicorn)的Web服务器rack.hijack.(Puma符合此标准,但在性能上Unicorn 相当.)

有了这个假设,我尝试EventMachine not initialized使用最直接的方法解决错误,即初始化EventMachine,方法是在初始化程序中插入以下代码config/initializers/eventmachine.rb:

Thread.new { EventMachine.run } unless EventMachine.reactor_running? && EventMachine.reactor_thread.alive?
Run Code Online (Sandbox Code Playgroud)

...... 成功!

我已经能够使用没有独立服务器模式基于事件的服务器通过单个端口在我的本地服务器上运行Websocket Rails.(关于ruby 2.1.3p242的Rails 4.1.6)

只要您对Web服务器选择没有限制,这应该适用于Heroku.

警告:这不是websocket-rails的官方支持配置.使用多线程Web服务器(如Puma)时必须小心,因为您的代码及其依赖项的代码必须是线程安全的.(临时?)解决方法是将每个工作者的最大线程数限制为1并增加工作者数量,从而实现类似于Unicorn的系统.


出于好奇,我在解决了上述问题后再次尝试了Unicorn:

  • 第一个websocket连接是由web服务器(Started GET "/websocket" for ...)接收的,但是statewebsocket客户端的连接被卡住了connecting,似乎无限期地挂起.

  • 第二个连接导致HTTP错误代码500,并app error: deadlock; recursive locking (ThreadError)显示在服务器控制台输出中.

通过(可能危险的)删除操作Rack::Lock,可以解决死锁错误,但连接仍然挂起,即使服务器控制台显示连接已被接受.

不出所料,这失败了.从错误消息中,我认为Unicorn由于与其网络架构(线程/并发)相关的原因而不兼容.但话说回来,它可能只是这个特定Rack中间件中的一些错误......

有谁知道为什么Unicorn不兼容的具体技术原因?


原始答案:

您是否检查过Web服务器和WebSocket服务器及其调试日志的端口?这些错误消息听起来像是连接到WebSocket服务器以外的其他东西.

一个关键在你已经使用了两个Web服务器的区别似乎是一个()是基于EventMachine的和一个(独角兽)不是.该网页套接字的Rails项目wiki指出,一个独立服务器模式必须用于非基于EventMachine的,网络服务器,如独角兽(因为它需要这需要一个更复杂的在Heroku上安装Redis的服务器).该错误消息RuntimeError (EventMachine not initialized: evma_install_oneshot_timer):表明未使用独立模式.

Heroku AFAIK只在外部公开一个内部端口(作为环境变量提供)作为端口80.WebSocket服务器通常需要自己的套接字地址(端口号)(可以通过反向代理WebSocket服务器来解决).Websocket-Rails似乎通过挂钩现有的基于EventMachine的Web服务器(Unicorn不提供) 劫持Rack来解决这个限制.