Why does turbo_stream_from not connect to the rails backend on my staging environment?

121 views Asked by At

A view in my rails application subscribes to a turbo stream channel with <%= turbo_stream_from session["_csrf_token"] %>. (I use the csrf token as channel name because the stream is meant to be per session.) In my controller, there is an action which triggers Turbo::StreamsChannel.broadcast_replace_to session["_csrf_token"], partial: "devise/registrations/creating", target: "registration_new_full_page". That action replaces the registration form with a loading view before redirecting, given the registration was successful.

In my local development environment, which I access with http://127.0.0.1:3000, everything works just fine. When loading the registration page, the logs show Turbo::StreamsChannel is streaming from TrJhUDOIuzZEKUER3tuC6qsNRsKovL6XEI63bKSuXrk which is what I'd expect.

Unfortunately, on my staging environment that exact log line is not shown any more. The broadcasted update is not received and nothing happens. Also, the HTML of the registration page in the browser shows <turbo-cable-stream-source channel="Turbo::StreamsChannel" signed-stream-name="..." connected=""></turbo-cable-stream-source> for the local development environment, but on the staging environment, that same line is missing connected="".

My staging environment uses an nginx to proxy requests to rails (running on a different machine). My nginx config contains this:

map $http_host $rails {
  myapp.com 123.123.123.123;
  myapp-staging.com 234.234.234.234;
}

...

  location /cable {
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Forwarded-Ssl on; # Optional
    proxy_set_header X-Forwarded-Port $server_port;
    proxy_set_header X-Forwarded-Host $host;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "Upgrade";
    proxy_set_header X-Real-IP $remote_addr;

    proxy_pass http://$rails;
  }

  location / {
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Forwarded-Ssl on; # Optional
    proxy_set_header X-Forwarded-Port $server_port;
    proxy_set_header X-Forwarded-Host $host;
    proxy_set_header X-Real-IP $remote_addr;

    proxy_redirect off;

    proxy_read_timeout 120;
    proxy_connect_timeout 120;
    proxy_send_timeout 120;

    proxy_pass http://$rails;
  }

and I don't see any messages in the browser console that do not appear in the local development environment.

The application uses Rails 7.1.2. There are no errors showing up in the rails or nginx logs.

I tried subscribing to a channel with a static string instead of the crsf-token, but that did not work either. I don't really understand that, it looks like rails is simply ignoring the channel subscription and broadcasting.

Another difference I have noticed between development and staging environment is that, in the browser network tab in the dev tools, a new keepalive get request is sent every 10 seconds to wss://myapp-staging.com/cable returning a 101 http status and showing up as Successfully upgraded to WebSocket in the rails log. That looks ok to me, but I don’t see that in the local development environment. That might be unrelated though, I don't know.

What am I missing here? Any idea what I could be doing wrong? Any help with this would be greatly appreciated.

1

There are 1 answers

0
squeezeitthroughthekeyhole On BEST ANSWER

Answering my own question so people with the same problem can find this.

It turned out that cable was not connecting correctly to redis. Adding proxy_http_version 1.1; to the /cable location block in the nginx configuration fixed the issue.