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
Running via Spring preloader in process 98344
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
Running via Spring preloader in process 98485
Loading development environment (Rails 5.1.0)
>> ExampleJob.perform_later
Enqueued ExampleJob (Job ID: bb6e9781-8ffb-4bf2-8dfc-8ac983ed8bf6)
to Async(default)
=> #<ExampleJob:0x007f816d466680 @arguments=[],
@job_id="bb6e9781-8ffb-4bf2-8dfc-8ac983ed8bf6", @queue_name="default",
@priority=nil, @executions=0,
@provider_job_id="263a31ae-b33d-4a12-a603-22dfbba9cab7">
>> Performing ExampleJob (Job ID: bb6e9781-8ffb-4bf2-8dfc-8ac983ed8bf6)
from Async(default)
Just waited 10 seconds.
Performed ExampleJob (Job ID: bb6e9781-8ffb-4bf2-8dfc-8ac983ed8bf6)
from Async(default) in 10012.97ms
?> 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'
$ bundle install
In config/application.rb
you can configure
the use of it:
require_relative 'boot'
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
# Initialize configuration defaults for originally generated Rails version.
config.load_defaults 5.1
# 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.
# Sidekiq Configuration
config.active_job.queue_adapter = :sidekiq
end
end