Integrating Action Cable with Passenger Standalone
Passenger Standalone is fully compatible with Action Cable. There are two ways to setup Action Cable with Passenger Standalone:
- Running the Action Cable server as part of the normal Rails application (default)
- Running the Action Cable server as a separate Passenger Standalone instance
Table of contents
- Loading...
Running the Action Cable server as part of the normal Rails application
This is the default setup as recommended by Rails and is also the easiest. It works by mounting ActionCable.server
to a certain path in your config/routes.rb
. That way, your Action Cable server will be running on the same host and port as your application, but under a sub-URI.
Requirements
- You need at least Passenger 5.0.25.
- You need Redis, PostgreSQL, or any other inter-process adapter supported by Action Cable.
- You need to use Passenger Standalone with the 'nginx' engine (which is the default). This setup does not work with the 'builtin' engine.
Step 1: configuring Passenger
Suppose that your routes.rb contains a call which mounts the Action Cable server at a certain path:
# Serve websocket cable requests in-process
mount ActionCable.server => '/cable'
To make this work in Passenger Standalone, you need to tell Passenger that you are running Action Cable inside your Rails application, and you need to tell Passenger what path it's listening on. In your Passengerfile.json, specify the --unlimited-concurrency-path
/ "unlimited_concurrency_paths" option:
{
"unlimited_concurrency_paths": [
"/cable"
]
}
Replace /cable
with the actual Action Cable path as is specified in your routes.rb.
Step 2: configuring 'config/cable.yml'
Passenger runs the Action Cable internally as a separate process. (Although the routes.rb comment says that mounting ActionCable.server is meant for serving it in-process, Passenger actually insists on running it as a separate process.) Action Cable defaults to the 'async' adapter, which does not work when multiple processes are involved. So you need to configure Action Cable to use a different adapter, such as Redis or PostgreSQL.
Here is an example that configures config/cable.yml to use Redis:
production:
adapter: redis
url: redis://redis.example.com:6379
local: &local
adapter: redis
url: redis://localhost:6379
development: *local
test: *local
Don't forget to start Redis.
Running the Action Cable server as a separate Passenger Standalone instance
You can also run the Action Cable server in a separate Passenger Standalone instance. This approach allows you to scale out the Action Cable server separately from the normal Rails application processes, and also allows you to put the Action Cable server on a separate host/port.
Requirements
- You need at least Passenger 5.0.24.
- You need Redis, PostgreSQL, or any other inter-process adapter supported by Action Cable.
Preparation: configure Action Cable
Before configuring Passenger, you need to decide on a hostname and port for your Action Cable server. Open config/environments/development.rb
or config/environments/production.rb
and specify your choice in the config.action_cable.url
option.
Furthermore, Passenger will run the Action Cable internally as a separate process. Action Cable defaults to the 'async' adapter, which does not work when multiple processes are involved. So you need to configure Action Cable to use a different adapter, such as Redis or PostgreSQL.
Here is an example that configures config/cable.yml to use Redis:
production:
adapter: redis
url: redis://redis.example.com:6379
local: &local
adapter: redis
url: redis://localhost:6379
development: *local
test: *local
Don't forget to start Redis.
Step 1: create a Rackup file
This setup requires a Rackup configuration file specifically for Action Cable. It is recommended that you call it cable/config.ru
. A basic Rackup configuration for Action Cable looks as follows:
require ::File.expand_path('../../config/environment', __FILE__)
Rails.application.eager_load!
run ActionCable.server
Step 2: create a 'bin/cable' script
Create a bin/cable
script, whose purpose is to start a Passenger Standalone instance with the Action Cable server inside it. It should contain:
#!/bin/sh
exec bundle exec passenger start -p YOUR_ACTION_CABLE_PORT_NUMBER_HERE -R cable/config.ru --force-max-concurrent-requests-per-process 0
The above code assumes that you have Passenger in your Gemfile. If you don't have Passenger in your Gemfile, then replace bundle exec
with env NOEXEC_EXCLUDE=passenger
, like this:
#!/bin/sh
exec env NOEXEC_EXCLUDE=passenger passenger start -p YOUR_ACTION_CABLE_PORT_NUMBER_HERE -R cable/config.ru --force-max-concurrent-requests-per-process 0
The --force-max-concurrent-requests-per-process
/ "force_max_concurrent_requests_per_process" option tunes Passenger for optimal WebSocket performance.
When done, make the file executable:
$ chmod +x bin/cable
Step 3: start Passenger
Run the bin/cable
script:
$ ./bin/cable
Congratulations, you are done!
Restarting the Action Cable server
Main article: Restarting applications
If you want to restart the Action Cable server, then you must use the passenger-config restart-app
command. Touching restart.txt
does not work well, because restart.txt is checked at the beginning of every new request. But WebSockets are persistent, so restart.txt won't be checked often.