Skip to content Skip to sidebar Skip to footer

Websockets Not Working In My Rails App When I Run On Unicorn Server, But Works On A Thin Server

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 hav

Solution 1:

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 serverwithoutStandalone 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.

Post a Comment for "Websockets Not Working In My Rails App When I Run On Unicorn Server, But Works On A Thin Server"