Rob Zolkos avatar

Rob Zolkos

February 21, 2024

(How I) Deploy Solid Queue with Capistrano

I manage a small number of Rails apps that haven’t yet migrated to Kamal for deployment but I wanted to migrate to solid_queue asap to reduce the service burden of running redis.

These applications are deployed with Capistrano on Ubuntu LTS servers and the solid_queue is managed by linux’s systemd. There isn’t much information out there on how to deploy solid_queue with Capistrano so hopefully this helps those of you that still use this popular way of deploying Rails applications.

The systemd service is defined in a file located in your deploy users home folder

/home/<deploy user>/.config/systemd/user/solid_queue.service

It looks like this (you may want to update Ruby versions and paths and such)

[Unit]
Description=solid_queue for app
After=syslog.target network.target

[Service]
Type=simple
Environment=RAILS_ENV=production
WorkingDirectory=/home/<deploy user>/apps/<app name>/current
ExecStart=/usr/local/bin/chruby-exec ruby-3.3.0 -- bundler exec rake solid_queue:start
ExecReload=/bin/kill -TSTP $MAINPID
ExecStop=/bin/kill -TERM $MAINPID

Environment=MALLOC_ARENA_MAX=2

RestartSec=1
Restart=on-failure

SyslogIdentifier=solid_queue

[Install]
WantedBy=default.target

Once you have this file in place you need to enable it, start it and ensure that it runs even when your deploy user is logged out.

Reload the daemon so the new service is loaded systemctl --user daemon-reload

Start the service systemctl --user start solid_queue.service

Enable the service to start at boot systemctl --user enable solid_queue.service

Enable the service to keep running when deploy user is logged out sudo loginctl enable-linger

That should be the systemd part done. Next up is getting Capistrano configured to stop and start the solid_queue service during a deployment.

Here is the config I use in my deploy.rb file to get solid_queue systemd service to restart.

set :solid_queue_systemd_unit_name, "solid_queue.service"

namespace :solid_queue do
  desc "Quiet solid_queue (start graceful termination)"
  task :quiet do
    on roles(:app) do
      execute :systemctl, "--user", "kill", "-s", "SIGTERM", fetch(:solid_queue_systemd_unit_name), raise_on_non_zero_exit: false
    end
  end

  desc "Stop solid_queue (force immediate termination)"
  task :stop do
    on roles(:app) do
      execute :systemctl, "--user", "kill", "-s", "SIGQUIT", fetch(:solid_queue_systemd_unit_name), raise_on_non_zero_exit: false
    end
  end

  desc "Start solid_queue"
  task :start do
    on roles(:app) do
      execute :systemctl, "--user", "start", fetch(:solid_queue_systemd_unit_name)
    end
  end

  desc "Restart solid_queue"
  task :restart do
    on roles(:app) do
      execute :systemctl, "--user", "restart", fetch(:solid_queue_systemd_unit_name)
    end
  end
end

# SolidQueue hooks
after "deploy:starting", "solid_queue:quiet"
after "deploy:updated", "solid_queue:stop"
after "deploy:published", "solid_queue:start"
after "deploy:failed", "solid_queue:restart"

That is all I needed to do. No extra gems. It all works smoothly, you will see the solid_queue workers shutdown and then start again after the app is deployed.

Let me know if you see anything that can be improved.