我正在学习Ruby on Rails在Heroku上使用websocket构建实时web应用程序,但我不明白为什么在Unicorn服务器上运行时websocket连接失败。我已经将Rails应用程序配置为使用Procfile在Unicorn本地和Heroku上运行。。。
web: bundle exec unicorn -p $PORT -c ./config/unicorn.rb
我从CCD_ 1本地开始。在客户端上用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
在瘦服务器上本地运行它时,它工作得很好。
在过去的五个小时里,我一直在网上研究这个问题,但还没有找到解决方案。任何解决这个问题的想法,甚至从我的工具中获得更多信息的想法,都将不胜感激!
更新:我觉得奇怪的是,websocket rails只支持基于EventMachine的web服务器,而web socket rails所基于的faye websocket支持许多具有多线程功能的web服务器。
经过进一步的调查和测试,我意识到我之前的假设是错误的。websocket rails似乎需要一个支持rack.hijack
的多线程(因此没有Unicorn)web服务器,而不需要基于EventMachine的web服务器。(彪马符合这一标准,同时在性能上与独角兽相当。)
有了这个假设,我尝试使用最直接的方法,即初始化EventMachine,通过在初始化器config/initializers/eventmachine.rb
中插入以下代码来解决EventMachine not initialized
错误:
Thread.new { EventMachine.run } unless EventMachine.reactor_running? && EventMachine.reactor_thread.alive?
以及成功
我已经能够使用非基于EventMachine的服务器通过单个端口在本地服务器上运行Websocket Rails,而不使用独立服务器模式。(ruby 2.1.3p242上的轨道4.1.6)
这应该适用于Heroku,只要你在网络服务器的选择上没有限制。
警告:这不是官方支持的websocket rails配置。使用Puma等多线程web服务器时必须小心,因为您的代码及其依赖项必须是线程安全的。一个(临时的?)解决方法是将每个工作线程的最大线程数限制为一个,并增加工作线程数,从而实现类似于Unicorn的系统
出于好奇,我在修复了上述问题后再次尝试独角兽:
第一个websocket连接由web服务器(
Started GET "/websocket" for ...
)接收,但是websocket客户端的$foreman start
0卡在connecting
上,似乎挂起了无限期地第二次连接导致HTTP错误代码500以及
app error: deadlock; recursive locking (ThreadError)
显示在服务器控制台输出。
通过删除Rack::Lock
这一(潜在危险的)操作,可以解决死锁错误,但连接仍然挂起,即使服务器控制台显示连接已被接受。
不出所料,这次失败了。从错误消息中,我认为Unicorn由于其网络架构(线程/并发)相关的原因而不兼容。但话说回来,这可能只是这个特定的Rack中间件中的一些错误。。。
有人知道独角兽不兼容的具体技术原因吗?
原始答案:
您是否检查了web服务器和WebSocket服务器的端口及其调试日志?这些错误消息听起来像是在连接到WebSocket服务器之外的其他服务器。
您使用的两个web服务器的关键区别似乎是,一个(Thin)是基于EventMachine的,另一个(Unicornebsocket Rails项目wiki指出,独立服务器模式必须用于非基于EventMachine的web服务器,如Unicorn(这需要在Heroku上进行更复杂的设置,因为它需要Redis服务器) 错误消息。RuntimeError (EventMachine not initialized: evma_install_oneshot_timer):
表明未使用独立模式
Heroku AFAIK仅对外暴露一个内部端口(作为环境变量提供)作为端口80。WebSocket服务器通常需要自己的套接字地址(端口号)(可以通过反向代理WebSocket server来解决)。Websocket Rails似乎通过钩住现有的基于EventMachine的web服务器(Unicorn不提供)劫持Rack来绕过这一限制。