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

标签 javascript ruby-on-rails heroku websocket

我正在学习 Ruby on Rails 以在 Heroku 上使用 WebSockets 构建实时网络应用程序,但我无法弄清楚为什么在 Unicorn 服务器上运行时 websocket 连接失败。我将我的 Rails 应用程序配置为在本地和 Heroku 上使用 Procfile 在 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' 失败。在收到握手响应之前连接已关闭。

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

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

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

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

最佳答案

更新: 我发现很奇怪 websocket-rails 只支持基于 EventMachine 的网络服务器,而 faye-websocket websocket-rails 基于它,支持 many multithread-capable web servers .

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

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

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

然后....成功!

我已经能够使用 non-EventMachine-based server 通过单个端口在我的本地服务器上运行 Websocket Rails 没有 Standalone Server Mode . ( ruby 2.1.3p242 上的 Rails 4.1.6)

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

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


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

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

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

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

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

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


原始答案:

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

您使用的两个 Web 服务器的关键区别似乎是一个(Thin)是基于 EventMachine 的,另一个是(Unicorn) 不是。 Websocket Rails 项目维基声明 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 .

关于javascript - 当我在 Unicorn 服务器上运行时,Websockets 在我的 Rails 应用程序中不起作用,但在瘦服务器上运行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25657405/

相关文章:

javascript - Firefox 中的表单字段在按下后退按钮后不记得输入的数据

javascript - 使用事件发射器的简单发布/订阅系统

javascript - 纯JS和html跨域ajax到外域

ruby-on-rails - 在我的两台计算机上同步 Rails 开发环境

css - Rails 4 图像在生产中更大

heroku - 我可以有一个带域名的 heroku 免费应用程序吗?

python - 在 Python virtualenv 中查找每个编译模块的大小?

javascript - 在 GET 和 setState 之后无法读取数组,即使它在那里

ruby-on-rails - Heroku:rails:获取 "No such file to load -- URI (LoadError)"

django - 如何将文件直接从 Django admin 上传到 Amazon S3?缓解 Heroku 应用程序错误(超时)