27

I have a Rails 5 app which uses Action Cable for websocket functionality.

In my development environment everything works as expected and the browser clients successfully connect to the Action Cable channels.

In my production environment Action Cable was working at some point, but then suddenly stopped functioning without any immediate apparent cause.

If I change the RAILS_ENV to production while running the app on my development machine Action Cable works fine. Something seems different when running the app on the actual production machine although the basic environment is the same.

The specific error I see in the Chrome console:

mydomain.com/:1 WebSocket connection to 'wss://mydomain.com/cable' failed: WebSocket is closed before the connection is established. I get a similar error in other browsers so it doesn't appear to be browser related. I disabled any adblockers while testing just to be sure they do not interfere.

Development.rb ENV related setup:

config.action_cable.url = "ws://localhost:#{port}/cable"

Production.rb ENV related setup:

hostname = ENV.fetch('HOSTNAME')
  port = ENV.fetch('PORT')
  base_url = "#{hostname}:#{port}"

  config.action_cable.url = "wss://#{hostname}/cable"
  config.action_cable.allowed_request_origins = ["https://#{base_url}", "https://#{hostname}"]

I use Puma as a webserver. The webserver serves a SSL connection for which a valid certificate is installed. On the production machine Puma serves the application on port 3000 but this is forwarded to port 443 in the router.

The only notable difference with running the app on my dev machine and production is that in production SSL is used.

edwardmp
  • 6,339
  • 5
  • 50
  • 77
  • 1
    Are you using AWS? – Shannon Feb 19 '17 at 23:15
  • @Shannon Nope, hosted using docker containers on a Synology NAS – edwardmp Feb 20 '17 at 17:18
  • I can't comment on this issue for lack of rep; what are you using to serve this? Nginx? Apache? The fact that it works with `production` set locally indicates an issue with the web server configuration. What Docker container are you running? What OS is running on your NAS? Need all these infos. – FanaHOVA Feb 20 '17 at 18:12
  • Puma is the webserver as indicated. I'll edit the post include some more info. By the way, this should be a comment to my post, not an answer – edwardmp Feb 20 '17 at 18:14
  • Is your redis store working? If that's what you're using in production. – Amin Shah Gilani Feb 22 '17 at 21:01
  • I was having issues getting ActionCable working in production. Just from my frustration, thought I'd throw out an idea. It sounds like the configuration of the production server is configed wrong. Did you set the host to your production server? This was an issue for me. I wrote what my files are, if it helps to look through. Good luck! https://walshcostigan.wordpress.com/2017/02/20/instant-chat-with-actioncable5-on-heroku/ – gwalshington Feb 23 '17 at 19:46
  • There is a similar issue ont the puma-git: https://github.com/puma/puma/issues/1189 This guy solved it by downgrading to Rails `5.0.0.1` – Michael B Feb 24 '17 at 22:37

2 Answers2

8

I can now safely conclude this is a bug, probably in Rails/ActionCable itself. This is corroborated by other reports and as I told at one point it worked fine, this was when I used Rails 5.0.0.1. When I updated to 5.0.1 it broke and it remains broken on 5.0.2. I'm opening an issue on the GitHub issue tracker of the Rails project.

Edit July 2017: Rails did change something as to how it reads and writes to the Rack socket, however the actual webserver software you use needs to support these nonblocking read and write methods. In my case, Puma did not at that time hence websockets didn't work. For Puma there is now a new release with a workaround for this issue.

edwardmp
  • 6,339
  • 5
  • 50
  • 77
  • In my case, it was a wrong memoization of AR model, so corresponding model was not being loaded for different chat room. – elquimista Mar 09 '18 at 13:47
  • 3
    hi, I see the same thing in production on Rails 5.2.0 (with Puma 3.11) - and I am wondering whether you ever got around to fixing this? - and (if you do not mind sharing) how? – walt_die May 20 '19 at 05:21
2

As per your problem statement

  • Your Development environment works because you have set it to handle insecure web traffic but on your Production environment is set to handle secure traffic.

Development.rb ENV related setup:

config.action_cable.url = "ws://localhost:#{port}/cable"

Production.rb ENV related setup:

 config.action_cable.url = "wss://#{hostname}/cable"  

According to your network setup you have configured your SSL port redirection to port 3000 and serving web request from PUMA rb server.

Now the problem i see over here is wss://#{hostname} will try to listen on default port 443 for secure traffic instead your redirected port 3000

Mandar
  • 1,006
  • 11
  • 28
  • You are correct, on my dev machine I'm not using SSL. Port 443 is forwarded to 3000 so that shouldn't really make any difference, right? – edwardmp Feb 26 '17 at 16:28
  • You need to add port in url. Your hosting server puma will take care of manipulation of traffic. – Mandar Feb 26 '17 at 17:40
  • okay let me try that although there should be no difference due to forwarding between the two ports – edwardmp Feb 26 '17 at 17:41
  • Just to let you know that dis didn't make any difference as expected – edwardmp Mar 08 '17 at 00:56