【问题标题】:Websockets not working in my Rails app when I run on Unicorn server, but works on a Thin server当我在 Unicorn 服务器上运行时,Websockets 在我的 Rails 应用程序中不起作用,但在瘦服务器上运行
【发布时间】:2014-10-28 17:26:13
【问题描述】:

我正在学习 Ruby on Rails 以在 Heroku 上使用 WebSockets 构建实时 Web 应用程序,但我无法弄清楚为什么在 Unicorn 服务器上运行时 WebSocket 连接失败。我将我的 Rails 应用程序配置为使用 Procfile 在本地和 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'); //I update the URL before pushing to Heroku

...在 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):

奇怪的是,当我使用命令$rails s 在瘦服务器上本地运行它时,它运行良好。

过去五个小时我一直在网上研究这个问题,但没有找到解决方案。任何解决此问题的想法,甚至是从我的工具中获取更多信息的想法,都将不胜感激!

【问题讨论】:

    标签: javascript ruby-on-rails heroku websocket


    【解决方案1】:

    更新:我觉得奇怪的是 websocket-rails 只支持基于 EventMachine 的 Web 服务器,而 websocket-railsfaye-websocket基于,支持many multithread-capable web servers

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

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

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

    并且.... 成功!

    我已经能够使用non-EventMachine-based server 没有 Standalone Server ModeWebsocket Rails 在我的本地服务器上通过单个端口工作。 (Ruby 2.1.3p242 上的 Rails 4.1.6)

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

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


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

    • 第一个 websocket 连接被 web 服务器 (Started GET "/websocket" for ...) 接收到,但是 websocket客户端的state卡在connecting上,好像挂了 无限期。

    • 第二次连接导致 HTTP 错误代码 500 以及 app error: deadlock; recursive locking (ThreadError) 出现在 服务器控制台输出。

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

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

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


    原始答案:

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

    您使用的两个 Web 服务器的一个 key 差异似乎是一个 (Thin) 是基于 EventMachine 的,另一个 (Unicorn) 不是。 Websocket Rails 项目 wiki 声明 Standalone Server Mode 必须用于非基于 EventMachine 的 Web 服务器,例如 Unicorn(这需要在 Heroku 上进行更复杂的设置,因为它需要 Redis 服务器)。 错误消息RuntimeError (EventMachine not initialized: evma_install_oneshot_timer): 表明未使用独立模式

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

    【讨论】:

    • 我想知道是否有人可以提供有关此主题的更多信息。我目前在使用 heroku、unicorn 和 websocket-rails 时遇到了同样的问题。
    • @DavidHahn,在我花时间尝试配置 U​​nicorn 以使用 websocket-rails 之前,我最终切换到 Thin,在线程模式下运行。
    • 嗨@XA21X,尝试使用你的解决方案来使用PUMA,但没有成功,你能看看吗? stackoverflow.com/questions/32030064/…
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-21
    • 2012-07-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多