Join GitHub today
GitHub is home to over 28 million developers working together to host and review code, manage projects, and build software together.Sign up
Active Job Introduction
Rails 4.2 introduced Active Job. Active Job is a standard interface for interacting with job runners. Active Job can be configured to work with Sidekiq.
Note that more advanced Sidekiq features (
sidekiq_options) cannot be controlled or configured via ActiveJob, e.g. saving backtraces.
Active Job Setup
The Active Job adapter must be set to
:sidekiq or it will simply use the default
:async from Rails 5). This can be done in
config/application.rb like this:
class Application < Rails::Application # ... config.active_job.queue_adapter = :sidekiq end
We can use the generator to create a new job.
rails generate job Example
This above command will create
class ExampleJob < ActiveJob::Base # Set the Queue as Default queue_as :default def perform(*args) # Perform Job end end
Jobs can be added to the job queue from anywhere. We can add a job to the queue by:
At this point, Sidekiq will run the job for us. If the job for some reason fails, Sidekiq will retry as normal.
Customizing error handling
Activejob does not support the full richness of Sidekiq's
retry feature. Instead it has a simple abstraction for encoding retries upon encountering specific exceptions.
class ExampleJob < ActiveJob::Base rescue_from(ErrorLoadingSite) do retry_job wait: 5.minutes, queue: :low_priority end def perform(*args) # Perform Job end end
The default AJ retry scheme is 3 retries, 5 seconds apart. Once this is done (after 15-30 seconds), AJ will kick the job back to Sidekiq, where Sidekiq's retries with exponential backoff will take over.
Action Mailer now comes with a method named #deliver_later which will send emails asynchronously (your emails send in a background job). As long as Active Job is setup to use Sidekiq we can use #deliver_later. Unlike Sidekiq, using Active Job will serialize any activerecord instance with Global ID. Later the instance will be deserialized.
Mailers are queued in the queue mailers. Remember to start sidekiq processing that queue:
bundle exec sidekiq -q default -q mailers
To send a basic message to the Job Queue we can use:
If you would like to bypass the job queue and perform the job synchronously you can use:
With Sidekiq we had the option to send emails with a set delay. We can do this through Active Job as well.
Old syntax for delayed message in Sidekiq:
New syntax to send delayed message through Active Job:
UserMailer.welcome_email(@user).deliver_later(wait: 1.hour) UserMailer.welcome_email(@user).deliver_later(wait_until: 10.hours.from_now)
Rails's GlobalID feature allows serializing full ActiveRecord objects as an argument to
#perform, so that
def perform(user_id) user = User.find(user_id) user.send_welcome_email! end
can be replaced with
def perform(user) user.send_welcome_email! end
Unfortunately this means that if the
User record is deleted after the job is enqueued but before the
perform method is called, exception handling is different. With regular Sidekiq, you could handle this with
def perform(user_id) user = User.find_by(id: user_id) if user user.send_welcome_email! else # handle a deleted user record end end
perform(user) will instead
raise for a missing record exception as part of deserializing the
You can work around this with
class MyJob < ActiveJob::Base rescue_from ActiveJob::DeserializationError do |exception| # handle a deleted user record end # ... end
ActiveJob has its own Job ID which means nothing to Sidekiq. As of Rails 5 you can get Sidekiq's JID by using
job = SomeJob.perform_later jid = job.provider_job_id
Benchmarks show that ActiveJob is 2-20x times slower pushing jobs to Redis and has roughly 3x the processing overhead (with Rails 5.1.4 and Sidekiq 5.1.1). See issue #3782 for discussion.
Many of Sidekiq Pro and Sidekiq Enterprise's features will break in unpredictable ways if you try to use ActiveJob with those features. For instance, creating ActiveJobs within a Batch will work in the base case but fail if you use ActiveJob's retry mechanism in those jobs. When in doubt, don't mix your use of AJ with Sidekiq's native APIs.