---
title: "Control Resque through Capistrano using systemd"
description: "Run Resque background workers as a systemd user service and start, stop, and restart them straight from Capistrano deployments."
url: "https://qameta.com/posts/control-resque-throuh-capistrano-using-systemd/"
image: "https://qameta.com/posts/control-resque-throuh-capistrano-using-systemd/control-resque-throuh-capistrano-using-systemd.png"
---

# Control Resque through Capistrano using systemd

![Control Resque through Capistrano using systemd](https://qameta.com/posts/control-resque-throuh-capistrano-using-systemd/control-resque-throuh-capistrano-using-systemd.png)

Restarting a resque service using just a cap (Capistrano) command is handy and
sometimes needed.

Instead of relying on Capistrano plugins like
[capistrano-resque](https://github.com/seuros/capistrano-resque) that spawn and
track worker processes themselves, we let [systemd](https://systemd.io)
supervise the [Resque](https://github.com/resque/resque) workers. systemd
takes care of restarting crashed workers, starting them on boot, and
collecting their logs through `journalctl`. Capistrano then only has to send
`start`, `stop`, and `restart` commands to the already configured service,
exactly the same way you would do it by hand on the server.

## Prerequisites

* A Linux server with systemd, reachable via SSH with the same deploy user
  Capistrano uses (here called `deploy`).
* [Redis](https://redis.io) running and reachable from the application, as it
  is required by [Resque](https://github.com/resque/resque).
* The `resque` gem (and `resque-scheduler` if you use scheduled jobs) added to
  your `Gemfile`.
* A working Capistrano deployment with `current_path` pointing to the released
  code.

## Setup systemd to run resque

We run the worker as a **user service** (`systemctl --user`) instead of a
system service. This way it runs under the same unprivileged `deploy` user
Capistrano already uses to release the code, without requiring `sudo` or root
access on the server.

### Create the service file

On the server, as the `deploy` user, create the directory for user units and
add a unit file for the workers:

```sh
mkdir -p ~/.config/systemd/user
```

```ini
# ~/.config/systemd/user/myapp-resque-workers.service
[Unit]
Description=myapp resque background workers
After=network.target

[Service]
Type=simple
WorkingDirectory=/var/www/myapp/current
Environment=RAILS_ENV=production
Environment=QUEUE=*
ExecStart=/usr/bin/env bundle exec rake resque:work
Restart=always
RestartSec=5

[Install]
WantedBy=default.target
```

`WorkingDirectory` points to Capistrano's `current` symlink, so every restart
picks up the latest release automatically without touching the unit file
again.

### Allow the service to run without an active login

By default, systemd stops all user services of a user as soon as their last
SSH session ends. Enable lingering once for the `deploy` user so the worker
keeps running (and can start on boot) even without an open session:

```sh
sudo loginctl enable-linger deploy
```

Load and enable the new unit:

```sh
systemctl --user daemon-reload
systemctl --user enable myapp-resque-workers.service
systemctl --user start myapp-resque-workers.service
```

**ATTENTION:** Capistrano executes commands over a non-interactive SSH
session. On some systems this means `$XDG_RUNTIME_DIR` is not set, and
`systemctl --user` fails with `Failed to connect to bus`. If you run into
this, either enable lingering as shown above (which fixes it in most setups)
or export the variable explicitly before the `systemctl` call:

```sh
export XDG_RUNTIME_DIR="/run/user/$(id -u)"
```

## Create a rails/rake Task


```ruby
namespace :resque do
  desc "Start resque background workers"
  task :start do
    on roles(:app) do
      within "#{current_path}" do
        with rails_env: "#{fetch(:stage)}" do
          execute "systemctl --user start myapp-resque-workers.service"
        end
      end
    end
  end

  desc "Stop resque background services"
  task :stop do
    on roles(:app) do
      within "#{current_path}" do
        with rails_env: "#{fetch(:stage)}" do
          execute "systemctl --user stop myapp-resque-workers.service"
        end
      end
    end
  end

  desc "Restart resque background services"
  task :restart do
    on roles(:app) do
      within "#{current_path}" do
        with rails_env: "#{fetch(:stage)}" do
          execute "systemctl --user restart myapp-resque-workers.service"
        end
      end
    end
  end
end
```

## Using Capistrano to control Resque

To list all commands we have previously created just run this command in your
project:

```sh
% bundle exec cap --tasks | grep resque
cap resque:restart                 # Restart resque background services
cap resque:start                   # Start resque background workers
cap resque:stop                    # Stop resque background services
```

To restart Resque for production you may use:

```sh
% bundle exec cap production resque:restart
```

### Restart workers automatically on every deploy

Instead of calling `resque:restart` by hand after every deploy, hook it into
Capistrano's deploy flow in your `config/deploy.rb`. This makes sure the
workers always run the code of the release that was just published:

```ruby
namespace :deploy do
  after :publishing, "resque:restart"
end
```

## Summary

Letting systemd supervise the Resque workers instead of a Capistrano plugin
keeps the moving parts simple: systemd owns starting, restarting on crash, and
logging through `journalctl`, while Capistrano only sends `start`, `stop`, and
`restart` commands to the service, same as you would do it manually with
`systemctl`. Hooking `resque:restart` into the deploy flow makes sure every
release ends up with workers running the latest code, without any extra step
to remember.
