Sometimes a specific piece of code takes a long time to run but doesn’t need to run right away. An example is sending an e-mail after creating an order at the end of a online shopping workflow. It can take a couple of seconds to send an e-mail but you don’t want your user to wait for that to happen within the controller. It makes more sense to use a queueing mechanism for these tasks.
Active Job provides such a queueing system. You can create jobs which are being processed asynchronous by active job.
The quickest way to create a new job is the job generator. Lets create an example job which waits for 10 seconds and than logs an info message:
$ rails new shop [...] $ cd shop $ rails generate job example invoke test_unit create test/jobs/example_job_test.rb create app/jobs/example_job.rb $
All jobs are created in the app/jobs
directory. Please change the
app/jobs/example_job.rb
file accordingly:
class ExampleJob < ApplicationJob
queue_as :default
def perform(*args)
sleep 10
logger.info "Just waited 10 seconds."
end
end
You can test the job in your console with ExampleJob.perform_later
which creates it:
$ rails console Loading development environment (Rails 5.0.0) >> ExampleJob.perform_later Performing ExampleJob from Inline(default) Just waited 10 seconds. Performed ExampleJob from Inline(default) in 10014.5ms Enqueued ExampleJob (Job ID: f0b6937d-c2b4-4685-afe3-d571044b57a0) to Inline(default) => #<ExampleJob:0x007ffa99a3f020 @arguments=[], @job_id="f0b6937d-c2b4-4685-afe3-d571044b57a0", @queue_name="default", @priority=nil> >> exit $
The file log/development.log
now contains the logging output.
A more concrete example of using jobs you’ll find in the Action Mailer chapter where an e-mail gets send.
The set
method provides two arguments which can be used to set
the execution of a job in the future:
-
wait
ExampleJob.set(wait: 1.hour).perform_later
-
wait_until
ExampleJob.set(wait_until: Date.tomorrow.noon).perform_later
== Configure the Job Server Backend
The page http://api.rubyonrails.org/classes/ActiveJob/QueueAdapters.html lists all available backends. To use one of them you have to install
the needed gem. Here is an example for the use of the popular
Sidekiq. To use the gem you have to
add it to Gemfile
and run a bundle install
afterwards:
[...]
gem 'sidekiq'
In config/application.rb
you can configure
the use of it:
require File.expand_path('../boot', __FILE__)
require 'rails/all'
# Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production.
Bundler.require(*Rails.groups)
module Shop
class Application < Rails::Application
# Settings in config/environments/* take precedence over those specified here.
# Application configuration should go into files in config/initializers
# -- all .rb files in that directory are automatically loaded.
config.active_job.queue_adapter = :sidekiq
end
end