gem version

Tuning for Server Sent Events and WebSockets

Relevant selection for this article:

Nginx

Using SSE with WebSockets generally means that an application must handle multiple concurrent connections. Ruby applications usually can't do this and need a special configuration tweak.

Ruby concurrency tweak

Passenger's highly optimized load balancer assumes that Ruby apps can handle 1 (or thread-limited amount of) concurrent connection(s). This is usually the case and results in optimal load-balancing. But endpoints that deal with SSE/Websockets can handle many more concurrent connections, so the assumption leads to degraded performance.

Starting from version 5.0.25, you can use the unlimited_concurrency_paths option to override this. The example below shows how to set the concurrency to unlimited for the /special_websocket_endpoint:

{
  "unlimited_concurrency_paths": [
    "/special_websocket_endpoint"
  ]
}

In version 5.0.22-5.0.24, you can use the passenger_force_max_concurrent_requests_per_process configuration option to override this. It needs to be set through the Nginx configuration template:

# (using Nginx template)
server {
   root /webapps/my_app/public;

   # Use default concurrency for the app. But for the endpoint
   # /special_websocket_endpoint, force a different concurrency.
   location /special_websocket_endpoint {
       passenger_app_group_name foo_websocket;
       passenger_force_max_concurrent_requests_per_process 0;
   }
}

In Passenger 5.0.21 and below, none of the above options were available yet. In those versions you had to work around it by entering code below into config.ru to set the concurrency (on the entire app):

if defined?(PhusionPassenger)
  PhusionPassenger.advertised_concurrency_level = 0
end

Action Cable integration

Are you using Ruby on Rails with Action Cable? Please refer to our Action Cable integration guide.

Demo apps

You can find the Passenger SSE demo app here and the WebSocket demo app here.

light mode dark mode
Passenger 6 Passenger 6