当我运行在Unicorn服务器上时,Websockets在我的Rails应用程序中不起作用,但适用于瘦服务器 [英] Websockets not working in my Rails app when I run on Unicorn server, but works on a Thin server

查看:172
本文介绍了当我运行在Unicorn服务器上时,Websockets在我的Rails应用程序中不起作用,但适用于瘦服务器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

  web:bundle exec unicorn -p $ PORT -c ./config/unicorn.rb 

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

  var dispatcher = new WebSocketRails('0.0.0.0 :3000 /的WebSocket'); //在推送到Heroku之前更新网址

...在Chrome Javascript中出现以下错误控制台,'websocket连接到ws://0.0.0.0:3000 / websocket'失败。在收到握手响应之前连接已关闭。



...当我在Heroku上的Unicorn上运行它时,出现类似的错误Chrome Javascript控制台,'websocket连接到ws://myapp.herokuapp.com/websocket'失败。 websocket握手期间出错。意外的响应代码:500。



Heroku日志中的堆栈跟踪表示, RuntimeError(eventmachine未初始化:evma_install_oneshot_timer ):



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



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

>更新:我发现奇怪的是, websocket-rails 仅支持基于EventMachine的Web服务器,而 websocket-rails 基于,支持 faye-websocket faye / faye-websocket-rubyrel =noreferrer>支持多线程的web服务器。

经过进一步的调查和测试,我意识到我的早先的假设是错误的。不需要基于EventMachine的web服务器,websocket-rails 似乎需要支持机架的支持多线程的(不支持 Unicorn )web服务器.hijack 。 ( Puma 符合此标准,同时在性能上相当于 Unicorn 。)



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

  Thread。新的{EventMachine.run}除非EventMachine.reactor_running? &安培;&安培; EventMachine.reactor_thread.alive? 

和.... 成功! $ b

通过使用 Websocket Rails rel =noreferrer> - 基于EventMachine的服务器 without 独立服务器模式 。 (Rails 4.1.6 on ruby​​ 2.1.3p242)



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



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




出于好奇,我在修复上述问题后再次尝试了 Unicorn

第一个websocket连接被web服务器接收(开始GET/ websocket为... ),但是
websocket客户端的状态被卡在连接中,似乎无限期挂起

  • 第二个连接导致HTTP错误代码500以及 app
    错误:死锁;递归锁定(ThreadError)
    出现在
    服务器控制台输出中。




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

    不出所料,这失败了。从错误消息中,我认为由于与其网络体系结构(线程/并发)有关的原因,Unicorn 是不兼容的。但是,再次,这可能只是在这个特定的 Rack 中间件中的一些错误...



    有谁知道特定的技术为什么 Unicorn 不兼容?




    原始答案: b
    $ b

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



    在您使用的两个Web服务器中的一个区别似乎( Thin )是基于EventMachine的,而其中一个( Unicorn )不是。 Websocket Rails 项目wiki指出,独立服务器模式 必须用于基于非EventMachine的Web服务器,例如Unicorn(这需要在Heroku上进行更复杂的设置,因为它需要 Redis >服务器)。 错误消息 RuntimeError(EventMachine未初始化:evma_install_oneshot_timer):表明未使用独立模式

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


    I'm learning Ruby on Rails to build a real-time web app with WebSockets on Heroku, but I can't figure out why the websocket connection fails when running on a Unicorn server. I have my Rails app configured to run on Unicorn both locally and on Heroku using a Procfile...

    web: bundle exec unicorn -p $PORT -c ./config/unicorn.rb
    

    ...which I start locally with $foreman start. The failure occurs when creating the websocket connection on the client in javascript...

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

    ...with the following error in the Chrome Javascript console, 'websocket connection to ws://0.0.0.0:3000/websocket' failed. Connection closed before receiving a handshake response.

    ...and when I run it on Unicorn on Heroku, I get a similar error in the Chrome Javascript console, 'websocket connection to ws://myapp.herokuapp.com/websocket' failed. Error during websocket handshake. Unexpected response code: 500.

    The stack trace in the Heroku logs says, RuntimeError (eventmachine not initialized: evma_install_oneshot_timer):

    What's strange is that it works fine when I run it locally on a Thin server using the command $rails s.

    I've spent the last five hours researching this problem online and haven't found the solution. Any ideas for fixing this, or even ideas for getting more information out of my tools, would be greatly appreciated!

    解决方案

    UPDATE: I found it strange that websocket-rails only supported EventMachine-based web servers while faye-websocket which websocket-rails is based upon, supports many multithread-capable web servers.

    After further investigation and testing, I realised that my earlier assumption had been wrong. Instead of requiring an EventMachine-based web server, websocket-rails appears to require a multithread-capable (so no Unicorn) web server which supports rack.hijack. (Puma meets this criteria while being comparable in performance to Unicorn.)

    With this assumption, I tried solving the EventMachine not initialized error using the most direct method, namely, initializing EventMachine, by inserting the following code in an initializer config/initializers/eventmachine.rb:

    Thread.new { EventMachine.run } unless EventMachine.reactor_running? && EventMachine.reactor_thread.alive?
    

    and.... success!

    I have been able to get Websocket Rails working on my local server over a single port using a non-EventMachine-based server without Standalone Server Mode. (Rails 4.1.6 on ruby 2.1.3p242)

    This should be applicable on Heroku as long as you have no restriction in web server choice.

    WARNING: This is not an officially supported configuration for websocket-rails. Care must be taken when using multithreading web servers such as Puma, as your code and that of its dependencies must be thread-safe. A (temporary?) workaround is to limit the maximum threads per worker to one and increase the number of workers, achieving a system similar to Unicorn.


    Out of curiousity, I tried Unicorn again after fixing the above issue:

    • The first websocket connection was received by the web server (Started GET "/websocket" for ...) but the state of the websocket client was stuck on connecting, seeming to hang indefinitely.

    • A second connection resulted in HTTP error code 500 along with app error: deadlock; recursive locking (ThreadError) showing up in the server console output.

    By the (potentially dangerous) action of removing Rack::Lock, the deadlock error can be resolved, but connections still hang, even though the server console shows that the connections were accepted.

    Unsurprisingly, this fails. From the error message, I think Unicorn is incompatible due to reasons related to its network architecture (threading/concurrency). But then again, it might just be some some bug in this particular Rack middleware...

    Does anyone know the specific technical reason for why Unicorn is incompatible?


    ORIGINAL ANSWER:

    Have you checked the ports for both the web server and the WebSocket server and their debug logs? Those error messages sound like they are connecting to something other than a WebSocket server.

    A key difference in the two web servers you have used seems to be that one (Thin) is EventMachine-based and one (Unicorn) is not. The Websocket Rails project wiki states that a Standalone Server Mode must be used for non-EventMachine-based web servers such as Unicorn (which would require an even more complex setup on Heroku as it requires a Redis server). The error message RuntimeError (EventMachine not initialized: evma_install_oneshot_timer): suggests that standalone-mode was not used.

    Heroku AFAIK only exposes one internal port (provided as an environmental variable) externally as port 80. A WebSocket server normally requires its own socket address (port number) (which can be worked around by reverse-proxying the WebSocket server). Websocket-Rails appears to get around this limitation by hooking into an existing EventMachine-based web server (which Unicorn does not provide) hijacking Rack.

    这篇关于当我运行在Unicorn服务器上时,Websockets在我的Rails应用程序中不起作用,但适用于瘦服务器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆