Ruby on Rails

How to install Sidekiq to a Ruby on Rails project deployed on Dokku server

This minipost will guide you through all the required steps needed in order to successfully deploy a sidekiq service on a Ruby on Rails application. We will focus on herokuish servers, try to cover both Heroku and Dokku implementations, that are pretty much the same.

To start with, add Sidekiq gem to your Gemfile, by:

# Sidekiq
gem 'sidekiq', '~> 5.2.5'

and run:

$ bundle install 

inside the project directory.

Add the file config/initializers/sidekiq.rb and paste the following configuration content:

Sidekiq.configure_server do |config|
  config.redis = { url: "#{ENV['REDIS_URL']}/#{ENV['REDIS_SIDEKIQ_DB']}" }
end

Sidekiq.configure_client do |config|
  config.redis = { url: "#{ENV['REDIS_URL']}/#{ENV['REDIS_SIDEKIQ_DB']}" }
end

The project we are working on has the following characteristics:

ruby 2.6.1p33
rails 5.2.2
bundler 2.0.1

To support this setup, a custom buildpack is required on dokku server. Therefore, login to your Dokku server as deploy user and run the following:

dokku config:set --no-restart appname BUILDPACK_URL=https://github.com/heroku/heroku-buildpack-ruby.git#v199

At the latest version of the buildpack is 199, feel free to check github for the latest release version. With this BUILDPACK_URL you will get a herokuish deployment:

-----> Cleaning up...
-----> Building appname from herokuish...
-----> Adding BUILD_ENV to build environment...
-----> Fetching custom buildpack
-----> Ruby app detected
-----> Compiling Ruby/Rails
-----> Using Ruby version: ruby-2.6.1
-----> Installing dependencies using bundler 2.0.1

On your Dokku server create a redis service for the application, type:

dokku redis:create redis-appname

(where appname your RoR application name)

Waiting for container to be ready
=====> Redis container created: redis-appname
=====> Container Information
       Config dir:          /var/lib/dokku/services/redis/redis-appname/config
       Data dir:            /var/lib/dokku/services/redis/redis-appname/data
       Dsn:                 redis://redis-appname:[email protected]:6379
       Exposed ports:       -                        
       Id:                  XXXXXXXXXXXXXXXXXXXXXX
       Internal ip:         XXX.XX.X.X               
       Links:               -                        
       Service root:        /var/lib/dokku/services/redis/redis-appname
       Status:              running                  
       Version:             redis:4.0.11     

LInk redis service to your application(appname), by:

dokku redis:link redis-appname appname
-----> Setting config vars
       REDIS_URL:  redis://redis-appname:[email protected]:6379
-----> Restarting app appname
-----> Releasing appname (dokku/appname:latest)...
-----> Deploying appname (dokku/appname:latest)...
-----> App Procfile file found (/home/dokku/appname/DOKKU_PROCFILE)
-----> DOKKU_SCALE file found (/home/dokku/appname/DOKKU_SCALE)
=====> web=1
-----> Attempting pre-flight checks
       For more efficient zero downtime deployments, create a file CHECKS.
       See http://dokku.viewdocs.io/dokku/deployment/zero-downtime-deploys/ for examples
       CHECKS file not found in container: Running simple container check...
-----> Waiting for 10 seconds ...

Add Sidekiq configuration(config/sidekiq.yml) file:

---
:concurrency: 5

production:
  :concurrency: 5

:queues:
  - default
  - mailers
  - broadcasters

In the above snippet, I have used one more queue than :default and :mailers. Feel free to add below, all the queues you are using.

Add the relevant routes for Sidekiq UI to be mounted(config/routes.rb):

Rails.application.routes.draw do
  require 'sidekiq/web'
  
  # ----------------------------------------------------------------------
  # Monitoring
  scope :monitoring do
    # Sidekiq Basic Auth from routes on production environment
    Sidekiq::Web.use Rack::Auth::Basic do |username, password|
      ActiveSupport::SecurityUtils.secure_compare(::Digest::SHA256.hexdigest(username), ::Digest::SHA256.hexdigest(ENV["SIDEKIQ_AUTH_USERNAME"])) &
        ActiveSupport::SecurityUtils.secure_compare(::Digest::SHA256.hexdigest(password), ::Digest::SHA256.hexdigest(ENV["SIDEKIQ_AUTH_PASSWORD"]))
    end if Rails.env.production?

    mount Sidekiq::Web, at: '/sidekiq'
  end
  # ----------------------------------------------------------------------
end

In the above, I have used Sidekiq Basic HTTP Authentication from Rails Routes that requires two env vars, that will be set at a later step, on the Dokku server.

Update Ruby on Rails config.ru file:

# This file is used by Rack-based servers to start the application.
require_relative 'config/environment'
# Sidekiq
require 'sidekiq/web'

run Sidekiq::Web
run Rails.application

Configure application.rb to use Sidekiq as the ActiveJob Queue adapter(config/application.rb):

class Application < Rails::Application
  # Active Job adapter
  config.active_job.queue_adapter = :sidekiq
end

Add to your Procfile the following worker line:

worker: bundle exec sidekiq -C config/sidekiq.yml

Go to Dokku server and set all the required environment variables with --no-restart flag:

dokku config:set --no-restart appname REDIS_SIDEKIQ_DB=1 SIDEKIQ_AUTH_USERNAME=sidekiq SIDEKIQ_AUTH_PASSWORD=12345

With the --no-restart flag, the env vars will be available on the next deployment. Commit all the above changes on the project and deploy the code to Dokku server, by:

$ git push dokku master

After deployment succeeds, scale your application to initiate the worker responsible for Sidekiq:

dokku ps:scale appname web=1 worker=1

Navigate to the application’s URL to check that Sidekiq UI is working. If you have followed the setup in this guide, your Sidekiq UI should be available at a url like the following:

https://www.appname.com/monitoring/sidekiq