Active Job
Sometimes a specific piece of code takes a long time to run but doesn’t need to run right away. A classic example is sending an email after creating an order at the end of an online shopping workflow. Sending an email can take a long time, 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 processed asynchronously.
In Rails 8 the default queue adapter is
Solid Queue — a
database-backed, production-ready adapter written by the
Rails team. A fresh rails new myapp wires it up
automatically (both the gem and the tables) and in
production jobs are persisted to your database. For
development Rails still uses the in-process :async
adapter so you don’t even need a worker running to try
things out. This chapter uses the development defaults.
|
Create a New Job
The quickest way to create a new job is the job generator. Let’s create an example job which waits for 10 seconds and then logs an info message:
$ rails new shop
[...]
$ cd shop
$ bin/rails db:prepare
$ bin/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 enqueues it:
$ bin/rails console
Loading development environment (Rails 8.1.3)
irb(main):001> ExampleJob.perform_later
Enqueued ExampleJob (Job ID: 21526c3c-...) to Async(default)
Performing ExampleJob (Job ID: 21526c3c-...) from Async(default) enqueued at 2026-04-19T11:30:00Z
=> #<ExampleJob:... @arguments=[], @job_id="21526c3c-...", @queue_name="default", @executions=0>
Now you have to wait 10 seconds to see the following output in the console:
Just waited 10 seconds.
Performed ExampleJob (Job ID: 21526c3c-...) from Async(default) in 10012.97ms
irb(main):002> exit
The file log/development.log also contains the logging
output.
|
You’ll find a more concrete example of using jobs in the Action Mailer chapter where an email gets sent.
Set the time for future execution
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
Queues
A job can declare which queue it should live in:
class ExampleJob < ApplicationJob
queue_as :low_priority
# ...
end
With Solid Queue you can then control concurrency per queue from
config/queue.yml:
default: &default
dispatchers:
- polling_interval: 1
batch_size: 500
workers:
- queues: "*"
threads: 3
processes: 1
polling_interval: 0.1
For development you do not need to edit this file. For production
you typically run one dedicated worker process per machine with
bin/jobs (Rails 8 generates that binstub for you).
Running Jobs in Production
Because Solid Queue is database-backed, running jobs in production is as simple as starting the worker process next to the web process:
$ bin/jobs
bin/jobs picks up the configuration from config/queue.yml, and
Kamal (Rails 8’s default deployer) already wires it up as a
separate service — see Production.
Recurring Jobs
Solid Queue also understands a simple cron-style schedule file,
config/recurring.yml:
production:
clean_soft_deletes:
class: CleanSoftDeletesJob
queue: background
schedule: every day at 4am
The entries in this file are enqueued by the bin/jobs process as
regular Active Jobs.
Configure a Different Backend
If for some reason you don’t want Solid Queue, the page https://api.rubyonrails.org/classes/ActiveJob/QueueAdapters.html lists all available Active Job backends. To use one of them you have to install the needed gem. Here is an example for the popular Sidekiq (which uses Redis).
Add it to the Gemfile and run bundle install:
gem "sidekiq"
$ bundle install
In config/application.rb you can configure the adapter:
require_relative "boot"
require "rails/all"
Bundler.require(*Rails.groups)
module Shop
class Application < Rails::Application
config.load_defaults 8.1
# Use Sidekiq instead of Solid Queue
config.active_job.queue_adapter = :sidekiq
end
end
Then make sure a Redis server is running and start the Sidekiq
worker with bundle exec sidekiq.
| For the overwhelming majority of small and mid-sized Rails 8 applications the built-in Solid Queue is plenty. Only reach for an alternative backend when you have a specific reason (existing Redis infrastructure, specific enterprise requirements, or a workload that really needs something Solid Queue cannot express). |