Deploy AnyCable with Capistrano and systemd
Tags: systemd, devops, rails, capistrano
Published: 2019-07-04 14:52:16

---
title: Deploy AnyCable with Capistrano and systemd
published: true
description: Manage AnyCable and any other Ruby process with systemd and Capistrano
tags: systemd, devops, rails, capistrano  
canonical_url: https://jetrockets.pro/blog/deploy-anycable-with-capistrano-and-systemd
---

# Note

First of all, if you still don't know what is [AnyCable](https://anycable.io/) than probably you never tried websockets in Rails.
"WTF???" you probably will say, and you are right. Yes, we have ActionCable since Rails 5.x, but you really believe Ruby is suitable for real time web? I have bad news for you.

# Introduction

AnyCable brings performance, stability, and scalability to WebSockets in Ruby/Rails. For some reason, it lacks only one thing – deployment documentation.

We primary use AWS as an infrastructure solution and happy with it. Capistrano gives us power tool to run deploy scripts while AWS allows scaling fast and easy (yes, we don't need Docker :)). Every day we manage Unicorn, Puma, Sidekiq with custom Capistrano recipes and have no problem with it. Everything works smooth and seems right. With AnyCable you cannot use Capistrano so easy because AnyCable cannot be daemonized out of the box. I will run ahead and say that this was a starting point for a solid, unified deploy solution.

#### AnyCable meets systemd

After some considerations, I understood that Unicorn or Sidekiq or Puma are just the same system processes as Nginx or PG and they should be controlled by the system. You should facepalm me now :) What is used in modern Linux distros to manage services? Of course, it is `systemd`. So why not to use it to manage AnyCable?

First of all, let's create a new service for `anycable`.

```bash
# /etc/systemd/system/your-project-anycable.service

[Unit]
Description=anycable for your-project
After=syslog.target network.target

[Service]
Type=simple
Environment=RAILS_ENV=staging
WorkingDirectory=/path-to-your-project/current/
ExecStart=/bin/bash -lc 'bundle exec anycable' #additional arguments can be added here
ExecStop=/bin/kill -TERM $MAINPID
User=www
Group=www
UMask=0002
MemoryHigh=2G
MemoryMax=3G
MemoryAccounting=true
RestartSec=1
Restart=on-failure

[Install]
WantedBy=multi-user.target
```

I pretty sure 3 gigabytes will be enough for ruby process :) After adding new service don't forget to reload `systemd`.

```bash
systemctl daemon-reload
```

Now you can control your AnyCable instance:

```bash
sudo systemctl stop|start|restart your-project-anycable
```

And don't forget to enable AnyCable on boot:

```bash
systemctl enable your-project-anycable
```

Same approach should be applied to AnyCable-Go. Add new service, reload `systemd`, enable it on boot.

```bash
# /etc/systemd/system/your-anycable-go.service

[Unit]
Description=anycable-go for your-project
After=syslog.target network.target

[Service]
Type=simple
WorkingDirectory=/srv/www/go
ExecStart=/srv/www/go/bin/anycable-go -port 3334 --ssl_cert=/path/to/your/certificate.pem --ssl_key=/path/to/your/privkey.pem 
ExecStop=/bin/kill -TERM $MAINPID
UMask=0002
RestartSec=1
Restart=on-failure

[Install]
WantedBy=multi-user.target
```

The last is Capistrano, let's create a new recipe and add it to deploy scenario.

```ruby
# config/deploy/recipes/anycable.rb

# frozen_string_literal: true

namespace :anycable do
  task :stop do
    on roles(:sidekiq) do
      execute :sudo, :systemctl, :stop, fetch(:anycable_systemctl_service_name)
    end
  end

  task :start do
    on roles(:sidekiq) do
      execute :sudo, :systemctl, :start, fetch(:anycable_systemctl_service_name)
    end
  end

  task :restart do
    on roles(:sidekiq) do
      execute :sudo, :systemctl, :restart, fetch(:anycable_systemctl_service_name)
    end
  end
end
```

```ruby
# config/deploy/production.rb
...
set :anycable_systemctl_service_name, 'your-project-anycable'

after 'deploy:publishing', 'anycable:restart'
...
```

# In conclusion

Why **you** should use `systemd` to manage Ruby service and what services can be managed? 

As I already said AnyCable here is just an example and we already migrated Unicorn and Sidekiq to `systemd` too. With `systemd` your application gets:

* a unified way to start, stop, restart every part of it
* all required components will be loaded on boot
* you can quickly get status of your processes
* integrate with different monitoring services (e.g. Nagios), because they already have `systemd` integration.