ActiveJob provides an uniform interface for declaring and run backedn jobs. Note that it is just a wrapper, it relies on background processing. If no backend is set, the job is immediately executed. The backend is set like:
# Set in config/application.rb
# Be sure to have the adapter's gem in your Gemfile and follow
# the adapter's specific installation and deployment instructions.
config.active_job.queue_adapter = :sidekiq
Commonly used backends include delayed job, sidekiq, Resque. For comparison, please check Delayed Job vs Resque vs Sidekiq . delayed_job is easier to use, sidekiq is faster but replies on Redis.
We use Sidekiq as the backend. It has good document. Here is my configuration:
# 1. Configuration
# install redis
sudo apt-get install redis-server # 3.0.6
sudo service redis-server restart
# install sidekiq in Gemfile
gem 'sidekiq'
bundle install # 5.2.5
# config active job in config/application.rb
config.active_job.queue_adapter = :sidekiq # if not set, all jobs will perform immediately.
# Remember to start the sidekiq process
# use "RAILS_ENV=production" or "-e production/development" to specify environment.
bundle exec sidekiq # connect to localhost:6379/0 by default.
# 2. Jobs, example.
# create job app/jobs/notify_iftt.rb
class NotifyIftttJob < ApplicationJob
queue_as :default
include IftttHelper
def perform(tids)
# Do something later notify_ifttt(tids) if tids
end
end
# call it
tids = tids.map{|tid| tid.tid}
NotifyIftttJob.perform_later(tids) if tids # preform_now does not go to backend.
It works as:
It is very important to start the Sidekiq process. Otherwise, the jobs will stay in the Redis unprocessed.
# use RAILS_ENV or -e to specify environment
RAILS_ENV=production bundle exec sidekiq -e production bundle exec sidekiq -e production
# use -C to specify configuration.
bundle exec sidekiq -e production -C config/sidekiq.xml
# config/sidekiq.yml
:verbose: false
:concurrency: 25
:strict: false
:logfile: log/sidekiq.log :pidfile: tmp/pids/sidekiq.pid development:
:verbose: true
:concurrency: 15
:logfile: log/sidekiq_dev.log :pidfile: tmp/pids/sidekiq_dev.pid
production:
It is also important to process in correct Rails environment, otherwise, error ocurrs when processing it. For example, the job is stored by production Rails, but got by Sidekiq working on development Rails. So it is better to use different database for different environments or code bases. By default, Redis provides 16 databases (0-15). Race condition is problematic to have two sidekiq/rails shares the same database.
# config/initializers/sidekiq.rb
# Redis by default have 0-15 database. Must config both server and client.
Sidekiq.configure_server do |config|
if Rails.env.development?
config.redis = { url: 'redis://localhost:6379/15'}
else
config.redis = { url: 'redis://localhost:6379/0'}
end
end
Sidekiq.configure_client do |config|
if Rails.env.development?
config.redis = { url: 'redis://localhost:6379/15'}
else
config.redis = { url: 'redis://localhost:6379/0'}
end
end
Sidekiq provide a web interface.
# Add in config/routes.rb
require 'sidekiq/web'
require 'admin_constraint' # require admin for access
mount Sidekiq::Web => '/sys/sidekiq', :constraints => AdminConstraint.new
# lib/admin_constraint.rb
class AdminConstraint
def matches?(request)
return false unless request.session[:user_id]
user = User.find request.session[:user_id]
user && user.ADMIN?
end
end