Realtime Rails with AnyCable. If you have been using Rails…
By: Sharvy Ahmed
Tags: Scalability, Anycable, Ruby on Rails, High Performance, Actioncable

Photo by Andrew Neel on Unsplash

If you have been using Rails ActionCable for sometime, you know how slow and inconsistent it performs during high load. Let’s see how we can switch to a better alternate AnyCable. I had my system running in Digital Ocean in Ubuntu 18.04.

Update Gemfile:

gem "anycable-rails"

gem "redis", ">= 4.0"

Update cable.yml:

local: &local

adapter: any_cable production:

adapter: any_cable

channel_prefix: your_db_name_production development: *local

test: *local

Environment files need to be updated with new action cable url:

environments/development.rb

config.action_cable.url = "ws://localhost:3334/cable"

config.action_cable.allowed_request_origins = ['http://localhost:3000']

environments/production.rb

config.action_cable.url = "wss://your_domain_name.com:3334/cable"

config.action_cable.allowed_request_origins = ['https://your_domain_name.com']

Let’s add AnyCable related configurations in config/anycable.yml

development:

redis_url: redis://localhost:6379/0 production:

redis_url: redis://localhost:6379/0

access_logs_disabled: false

If you are using foreman to run all of your servers (in development), let’s update the Procfile:

rpc: bundle exec anycable

ws: anycable-go --port 3334 -headers=cookie,x-api-token,origin

You can find your (Devise) authenticated user like this:

def find_verified_user

session_key = Rails.application.config.session_options[:key]

env['rack.session'] = cookies.encrypted[session_key || raise("No cookies key in config")]



if verified_user = Warden::SessionSerializer.new(env).fetch(:user)

verified_user

else

reject_unauthorized_connection

end

end

At this moment your development environment is ready to work with AnyCable. You can test locally. Now lets run AnyCable servers in production.

Install Go Lang:

# run in production terminal sudo apt install golang-go go get -u -f github.com/anycable/anycable-go/cmd/anycable-go

We need to create two Systemd services to run two servers in the background.

# run in production terminal

sudo nano /etc/systemd/system/anycable-go.service

File contents will be like this if you are using Let’s Encrypt free SSL:

[Unit]

Description=AnyCable Go WebSocket Server

After=network.target [Service]

Type=simple

ExecStart=/home/your_deploy_user/go/bin/anycable-go --port 3334 -headers=cookie,x-api-token,origin --ssl_cert=/etc/letsencrypt/live/your_domain_name.com/fullchain.pem --ssl_key=/etc/letsencrypt/live/your_domain_name.com/privkey.pem ExecStop=/bin/kill -TERM $MAINPID

LimitNOFILE=16384 # increase open files limit (see OS Tuning guide)

Restart=on-failure # Configure WebSocket server using env vars

Environment=ANYCABLE_HOST=your_domain_name.com

Environment=ANYCABLE_REDIS_URL=redis://localhost:6379/0 [Install]

WantedBy=multi-user.target

For AnyCable RPC service:

# run in production terminal

sudo nano /etc/systemd/system/anycable-rpc.service

File contents will be like this:

[Unit]

Description=AnyCable gRPC Server

After=syslog.target network.target [Service]

Type=simple

Environment=RAILS_ENV=production

WorkingDirectory=/home/your_deploy_user/rails_app/current/ # if using rvm or rbenv

ExecStart=/bin/bash -lc 'bundle exec anycable'

# or else

# ExecStart=bundle exec anycable ExecStop=/bin/kill -TERM $MAINPID User=your_deploy_user UMask=0002

MemoryHigh=2G

MemoryMax=3G

MemoryAccounting=true

Restart=on-failure Environment=ANYCABLE_REDIS_URL=redis://localhost:6379/0 [Install]

WantedBy=multi-user.target

You need to reload daemon:

sudo systemctl daemon-reload

Let’s start our AnyCable-Go server and AnyCable-RPC server:

sudo systemctl start anycable-go anycable-rpc

If ufw is enabled, we need to allow port 3334:

sudo ufw allow 3334

That’s it! Make sure both the servers are running:

# run in production terminal sudo systemctl status anycable-go.service sudo systemctl status anycable-rpc.service

If both servers are showing active status, you can deploy your rails app to the production! Happy coding! :)