Active Job Basics
This guide provides you with all you need to get started in creating, enqueuingand executing background jobs.
After reading this guide, you will know:
- How to create and enqueue jobs.
- How to configure and use Solid Queue.
- How to run jobs in the background.
- How to send emails from your application asynchronously.
1. What is Active Job?
Active Job is a framework in Rails designed for declaring background jobs andexecuting them on a queuing backend. It provides a standardized interface fortasks like sending emails, processing data, or handling regular maintenanceactivities, such as clean-ups and billing charges. By offloading these tasksfrom the main application thread to a queuing backend like the default SolidQueue, Active Job ensures that time-consuming operations do not block therequest-response cycle. This can improve the performance and responsiveness ofthe application, allowing it to handle tasks in parallel.
2. Create and Enqueue Jobs
This section will provide a step-by-step guide to create a job and enqueue it.
2.1. Create the Job
Active Job provides a Rails generator to create jobs. The following will createa job inapp/jobs (with an attached test case undertest/jobs):
$bin/railsgenerate job guests_cleanupinvoke test_unitcreate test/jobs/guests_cleanup_job_test.rbcreate app/jobs/guests_cleanup_job.rbYou can also create a job that will run on a specific queue:
$bin/railsgenerate job guests_cleanup--queue urgentIf you don't want to use a generator, you could create your own file inside ofapp/jobs, just make sure that it inherits fromApplicationJob.
Here's what a job looks like:
classGuestsCleanupJob<ApplicationJobqueue_as:defaultdefperform(*guests)# Do something laterendendNote that you can defineperform with as many arguments as you want.
If you already have an abstract class and its name differs fromApplicationJob, you can pass the--parent option to indicate you want adifferent abstract class:
$bin/railsgenerate job process_payment--parent=payment_jobclassProcessPaymentJob<PaymentJobqueue_as:defaultdefperform(*args)# Do something laterendend2.2. Enqueue the Job
Enqueue a job usingperform_later and, optionally,set. Like so:
# Enqueue a job to be performed as soon as the queuing system is# free.GuestsCleanupJob.perform_laterguest# Enqueue a job to be performed tomorrow at noon.GuestsCleanupJob.set(wait_until:Date.tomorrow.noon).perform_later(guest)# Enqueue a job to be performed 1 week from now.GuestsCleanupJob.set(wait:1.week).perform_later(guest)# `perform_now` and `perform_later` will call `perform` under the hood so# you can pass as many arguments as defined in the latter.GuestsCleanupJob.perform_later(guest1,guest2,filter:"some_filter")That's it!
2.3. Enqueue Jobs in Bulk
You can enqueue multiple jobs at once usingperform_all_later.For more details seeBulk Enqueuing.
3. Default Backend: Solid Queue
Solid Queue, which is enabled by default from Rails version 8.0 and onward, is adatabase-backed queuing system for Active Job, allowing you to queue largeamounts of data without requiring additional dependencies such as Redis.
Besides regular job enqueuing and processing, Solid Queue supports delayed jobs,concurrency controls, numeric priorities per job, priorities by queue order, andmore.
3.1. Set Up
3.1.1. Development
In development, Rails provides an asynchronous in-process queuing system, whichkeeps the jobs in RAM. If the process crashes or the machine is reset, then alloutstanding jobs are lost with the default async backend. This can be fine forsmaller apps or non-critical jobs in development.
However, if you use Solid Queue instead, you can configure it in the same way asin the production environment:
# config/environments/development.rbconfig.active_job.queue_adapter=:solid_queueconfig.solid_queue.connects_to={database:{writing: :queue}}which sets the:solid_queue adapter as the default for Active Job in thedevelopment environment, and connects to thequeue database for writing.
Thereafter, you'd addqueue to the development database configuration:
# config/database.ymldevelopment:primary:<<:*defaultdatabase:storage/development.sqlite3queue:<<:*defaultdatabase:storage/development_queue.sqlite3migrations_paths:db/queue_migrateThe keyqueue from the database configuration needs to match the keyused in the configuration forconfig.solid_queue.connects_to.
You can then rundb:prepare to ensure thequeue database indevelopment has all the required tables:
$bin/railsdb:prepareYou can find the default generated schema for thequeue database indb/queue_schema.rb. They will contain tables likesolid_queue_ready_executions,solid_queue_scheduled_executions, and more.
Finally, to start the queue and start processing jobs you can run:
bin/jobs start3.1.2. Production
Solid Queue is already configured for the production environment. If you openconfig/environments/production.rb, you will see the following:
# config/environments/production.rb# Replace the default in-process and non-durable queuing backend for Active Job.config.active_job.queue_adapter=:solid_queueconfig.solid_queue.connects_to={database:{writing: :queue}}Additionally, the database connection for thequeue database is configured inconfig/database.yml:
# config/database.yml# Store production database in the storage/ directory, which by default# is mounted as a persistent Docker volume in config/deploy.yml.production:primary:<<:*defaultdatabase:storage/production.sqlite3queue:<<:*defaultdatabase:storage/production_queue.sqlite3migrations_paths:db/queue_migrateMake sure you rundb:prepare so your database is ready to use:
$bin/railsdb:prepare3.2. Configuration
The configuration options for Solid Queue are defined inconfig/queue.yml.Here is an example of the default configuration:
default:&defaultdispatchers:-polling_interval:1batch_size:500workers:-queues:"*"threads:3processes:<%= ENV.fetch("JOB_CONCURRENCY", 1) %>polling_interval:0.1In order to understand the configuration options for Solid Queue, you mustunderstand the different types of roles:
- Dispatchers: They select jobs scheduled to run for the future. When it'stime for these jobs to run, dispatchers move them from the
solid_queue_scheduled_executionstable to thesolid_queue_ready_executionstable so workers can pick them up. They also manage concurrency-relatedmaintenance. - Workers: They pick up jobs that are ready to run. These jobs are takenfrom the
solid_queue_ready_executionstable. - Scheduler: This takes care of recurring tasks, adding jobs to the queuewhen they're due.
- Supervisor: It oversees the whole system, managing workers anddispatchers. It starts and stops them as needed, monitors their health, andensures everything runs smoothly.
Everything is optional in theconfig/queue.yml. If no configuration isprovided, Solid Queue will run with one dispatcher and one worker with defaultsettings. Below are some of the configuration options you can set inconfig/queue.yml:
| Option | Description | Default Value |
|---|---|---|
| polling_interval | Time in seconds workers/dispatchers wait before checking for more jobs. | 1 second (dispatchers), 0.1 seconds (workers) |
| batch_size | Number of jobs dispatched in a batch. | 500 |
| concurrency_maintenance_interval | Time in seconds the dispatcher waits before checking for blocked jobs that can be unblocked. | 600 seconds |
| queues | List of queues workers fetch jobs from. Supports* for all queues or queue name prefixes. | * |
| threads | Maximum size of the thread pool for each worker. Determines how many jobs a worker fetches at once. | 3 |
| processes | Number of worker processes forked by the supervisor. Each process can dedicate a CPU core. | 1 |
| concurrency_maintenance | Whether the dispatcher performs concurrency maintenance work. | true |
You can read more about theseconfiguration options in the Solid Queuedocumentation.There are alsoadditional configurationoptionsthat can be set inconfig/<environment>.rb to further configure Solid Queue inyour Rails Application.
3.3. Queue Order
As per the configuration options in theConfiguration section,thequeues configuration option will list the queues that workers will pickjobs from. In a list of queues, the order matters. Workers will pick jobs fromthe first queue in the list - once there are no more jobs in the first queue,only then will it move onto the second, and so on.
# config/queue.ymlproduction:workers:-queues:[active_storage*, mailers]threads:3polling_interval:5In the above example, workers will fetch jobs from queues starting with"active_storage", like theactive_storage_analyse queue andactive_storage_transform queue. Only when no jobs remain in theactive_storage-prefixed queues will workers move on to themailers queue.
The wildcard* (like at the end of "active_storage") is only allowed onits own or at the end of a queue name to match all queues with the same prefix.You can't specify queue names such as*_some_queue.
Using wildcard queue names (e.g.,queues: active_storage*) can slowdown polling performance in SQLite and PostgreSQL due to the need for aDISTINCTquery to identify all matching queues, which can be slow on large tables in these RDBMS.For better performance, it’s best to specify exact queue names instead of usingwildcards. Read more about this inQueues specification and performance in theSolid Queue documentation
Active Job supports positive integer priorities when enqueuing jobs (seePriority section). Within a single queue, jobs are picked based ontheir priority (with lower integers being higher priority). However, when youhave multiple queues, the order of the queues themselves takes priority.
For example, if you have two queues,production andbackground, jobs in theproduction queue will always be processed first, even if some jobs in thebackground queue have a higher priority.
3.4. Threads, Processes, and Signals
In Solid Queue, parallelism is achieved through threads (configurable via thethreads parameter), processes (via theprocessesparameter), or horizontal scaling. The supervisor managesprocesses and responds to the following signals:
- TERM, INT: Starts graceful termination, sending a TERM signal and waitingup to
SolidQueue.shutdown_timeout. If not finished, a QUIT signal forcesprocesses to exit. - QUIT: Forces immediate termination of processes.
If a worker is killed unexpectedly (e.g., with aKILL signal), in-flight jobsare marked as failed, and errors likeSolidQueue::Processes::ProcessExitErrororSolidQueue::Processes::ProcessPrunedError are raised. Heartbeat settingshelp manage and detect expired processes. Read more aboutThreads, Processesand Signals in the Solid Queuedocumentation.
3.5. Errors When Enqueuing
Solid Queue raises aSolidQueue::Job::EnqueueError when Active Record errorsoccur during job enqueuing. This is different from theActiveJob::EnqueueErrorraised by Active Job, which handles the error and makesperform_later returnfalse. This makes error handling trickier for jobs enqueued by Rails orthird-party gems likeTurbo::Streams::BroadcastJob.
For recurring tasks, any errors encountered while enqueuing are logged, but theywon’t be raised. Read more aboutErrors When Enqueuing in the Solid Queuedocumentation.
3.6. Concurrency Controls
Solid Queue extends Active Job with concurrency controls, allowing you to limithow many jobs of a certain type or with specific arguments can run at the sametime. If a job exceeds the limit, it will be blocked until another job finishesor the duration expires. For example:
classMyJob<ApplicationJoblimits_concurrencyto:2,key:->(contact){contact.account},duration:5.minutesdefperform(contact)# perform job logicendendIn this example, only twoMyJob instances for the same account will runconcurrently. After that, other jobs will be blocked until one completes.
Thegroup parameter can be used to control concurrency across different jobtypes. For instance, two different job classes that use the same group will havetheir concurrency limited together:
classBox::MovePostingsByContactToDesignatedBoxJob<ApplicationJoblimits_concurrencykey:->(contact){contact},duration:15.minutes,group:"ContactActions"endclassBundle::RebundlePostingsJob<ApplicationJoblimits_concurrencykey:->(bundle){bundle.contact},duration:15.minutes,group:"ContactActions"endThis ensures that only one job for a given contact can run at a time, regardlessof the job class.
Read more aboutConcurrency Controls in the Solid Queuedocumentation.
3.7. Error Reporting on Jobs
If your error tracking service doesn’t automatically report job errors, you canmanually hook into Active Job to report them. For example, you can add arescue_from block inApplicationJob:
classApplicationJob<ActiveJob::Baserescue_from(Exception)do|exception|Rails.error.report(exception)raiseexceptionendendIf you use ActionMailer, you’ll need to handle errors forMailDeliveryJobseparately:
classApplicationMailer<ActionMailer::BaseActionMailer::MailDeliveryJob.rescue_from(Exception)do|exception|Rails.error.report(exception)raiseexceptionendend3.8. Transactional Integrity on Jobs
⚠️ Having your jobs in the same ACID-compliant database as your application dataenables a powerful yet sharp tool: taking advantage of transactional integrityto ensure some action in your app is not committed unless your job is also committedand vice versa, and ensuring that your job won't be enqueued until the transactionwithin which you're enqueuing it is committed. This can be very powerful and useful,but it can also backfire if you base some of your logic on this behavior,and in the future, you move to another active job backend, or if you simply moveSolid Queue to its own database, and suddenly the behavior changes under you.
Because this can be quite tricky and many people shouldn't need to worry about it,by default Solid Queue is configured in a different database as the main app.
However, if you use Solid Queue in the same database as your app, you can make sure youdon't rely accidentallly on transactional integrity with Active Job’senqueue_after_transaction_commit option which can be enabled for individual jobs orall jobs throughApplicationJob:
classApplicationJob<ActiveJob::Baseself.enqueue_after_transaction_commit=trueendYou can also configure Solid Queue to use the same database as your app whileavoiding relying on transactional integrity by setting up a separate databaseconnection for Solid Queue jobs. Read more aboutTransactional Integrity in theSolid Queuedocumentation
3.9. Recurring Tasks
Solid Queue supports recurring tasks, similar to cron jobs. These tasks aredefined in a configuration file (by default,config/recurring.yml) and can bescheduled at specific times. Here's an example of a task configuration:
production:a_periodic_job:class:MyJobargs:[42,{status:"custom_status"}]schedule:every seconda_cleanup_task:command:"DeletedStuff.clear_all"schedule:every day at 9amEach task specifies aclass orcommand and aschedule (parsed usingFugit). You can also pass arguments tojobs, such as in the example forMyJob whereargs are passed. This can bepassed as a single argument, a hash, or an array of arguments that can alsoinclude kwargs as the last element in the array. This allows jobs to runperiodically at specified times.
Read more aboutRecurring Tasks in the Solid Queuedocumentation.
3.10. Job Tracking and Management
A tool likemission_control-jobs can helpcentralize the monitoring and management of failed jobs. It provides insightsinto job statuses, failure reasons, and retry behaviors, enabling you to trackand resolve issues more effectively.
For instance, if a job fails to process a large file due to a timeout,mission_control-jobs allows you to inspect the failure, review the job’sarguments and execution history, and decide whether to retry, requeue, ordiscard it.
4. Queues
With Active Job you can schedule the job to run on a specific queue usingqueue_as:
classGuestsCleanupJob<ApplicationJobqueue_as:low_priority# ...endYou can prefix the queue name for all your jobs usingconfig.active_job.queue_name_prefix inapplication.rb:
# config/application.rbmoduleYourAppclassApplication<Rails::Applicationconfig.active_job.queue_name_prefix=Rails.envendend# app/jobs/guests_cleanup_job.rbclassGuestsCleanupJob<ApplicationJobqueue_as:low_priority# ...end# Now your job will run on queue production_low_priority on your# production environment and on staging_low_priority# on your staging environmentYou can also configure the prefix on a per job basis.
classGuestsCleanupJob<ApplicationJobqueue_as:low_priorityself.queue_name_prefix=nil# ...end# Now your job's queue won't be prefixed, overriding what# was configured in `config.active_job.queue_name_prefix`.The default queue name prefix delimiter is '_'. This can be changed by settingconfig.active_job.queue_name_delimiter inapplication.rb:
# config/application.rbmoduleYourAppclassApplication<Rails::Applicationconfig.active_job.queue_name_prefix=Rails.envconfig.active_job.queue_name_delimiter="."endend# app/jobs/guests_cleanup_job.rbclassGuestsCleanupJob<ApplicationJobqueue_as:low_priority# ...end# Now your job will run on queue production.low_priority on your# production environment and on staging.low_priority# on your staging environmentTo control the queue from the job level you can pass a block toqueue_as. Theblock will be executed in the job context (so it can accessself.arguments),and it must return the queue name:
classProcessVideoJob<ApplicationJobqueue_asdovideo=self.arguments.firstifvideo.owner.premium?:premium_videojobselse:videojobsendenddefperform(video)# Do process videoendendProcessVideoJob.perform_later(Video.last)If you want more control on what queue a job will be run you can pass a:queueoption toset:
MyJob.set(queue: :another_queue).perform_later(record)If you choose to use analternate queuingbackend you may need to specify the queues tolisten to.
5. Priority
You can schedule a job to run with a specific priority usingqueue_with_priority:
classGuestsCleanupJob<ApplicationJobqueue_with_priority10# ...endSolid Queue, the default queuing backend, prioritizes jobs based on the order ofthe queues. You can read more about it in theOrder of Queuessection. If you're using Solid Queue, and both the order of thequeues and the priority option are used, the queue order will take precedence,and the priority option will only apply within each queue.
Other queuing backends may allow jobs to be prioritized relative to otherswithin the same queue or across multiple queues. Refer to the documentation ofyour backend for more information.
Similar toqueue_as, you can also pass a block toqueue_with_priority to beevaluated in the job context:
classProcessVideoJob<ApplicationJobqueue_with_prioritydovideo=self.arguments.firstifvideo.owner.premium?0else10endenddefperform(video)# Process videoendendProcessVideoJob.perform_later(Video.last)You can also pass a:priority option toset:
MyJob.set(priority:50).perform_later(record)If a lower priority number performs before or after a higher prioritynumber depends on the adapter implementation. Refer to documentation of yourbackend for more information. Adapter authors are encouraged to treat a lowernumber as more important.
6. Job Continuations
Jobs can be split into resumable steps using continuations. This is useful whena job may be interrupted - for example, during queue shutdown. When usingcontinuations, the job can resume from the last completed step, avoiding theneed to restart from the beginning.
To use continuations, include theActiveJob::Continuable module. You can thendefine each step using thestep method inside theperform method. Each step canbe declared with a block or by referencing a method name.
classProcessImportJob<ApplicationJobincludeActiveJob::Continuabledefperform(import_id)# Always runs on job start, even when resuming from an interrupted step.@import=Import.find(import_id)# Step defined using a blockstep:initializedo@import.initializeend# Step with a cursor — progress is saved and resumed if the job is interruptedstep:processdo|step|@import.records.find_each(start:step.cursor)do|record|record.processstep.advance!from:record.idendend# Step defined by referencing a methodstep:finalizeendprivatedeffinalize@import.finalizeendendEach step runs sequentially. If the job is interrupted between steps, or within astep that uses a cursor, the job resumes from the last recorded position. Thismakes it easier to build long-running or multi-phase jobs that can safely pauseand resume without losing progress.For more details, seeActiveJob::Continuation.
7. Callbacks
Active Job provides hooks to trigger logic during the life cycle of a job. Likeother callbacks in Rails, you can implement the callbacks as ordinary methodsand use a macro-style class method to register them as callbacks:
classGuestsCleanupJob<ApplicationJobqueue_as:defaultaround_perform:around_cleanupdefperform# Do something laterendprivatedefaround_cleanup# Do something before performyield# Do something after performendendThe macro-style class methods can also receive a block. Consider using thisstyle if the code inside your block is so short that it fits in a single line.For example, you could send metrics for every job enqueued:
classApplicationJob<ActiveJob::Basebefore_enqueue{|job|$statsd.increment"#{job.class.name.underscore}.enqueue"}end7.1. Available Callbacks
Please note that when enqueuing jobs in bulk usingperform_all_later,callbacks such asaround_enqueue will not be triggered on the individual jobs.SeeBulk Enqueuing Callbacks.
8. Bulk Enqueuing
You can enqueue multiple jobs at once usingperform_all_later.Bulk enqueuing reduces the number of round trips to the queue data store (likeRedis or a database), making it a more performant operation than enqueuing thesame jobs individually.
perform_all_later is a top-level API on Active Job. It accepts instantiatedjobs as arguments (note that this is different fromperform_later).perform_all_later does callperform under the hood. The arguments passed tonew will be passed on toperform when it's eventually called.
Here is an example callingperform_all_later withGuestsCleanupJob instances:
# Create jobs to pass to `perform_all_later`.# The arguments to `new` are passed on to `perform`cleanup_jobs=Guest.all.map{|guest|GuestsCleanupJob.new(guest)}# Will enqueue a separate job for each instance of `GuestsCleanupJob`ActiveJob.perform_all_later(cleanup_jobs)# Can also use `set` method to configure options before bulk enqueuing jobs.cleanup_jobs=Guest.all.map{|guest|GuestsCleanupJob.new(guest).set(wait:1.day)}ActiveJob.perform_all_later(cleanup_jobs)perform_all_later logs the number of jobs successfully enqueued, for exampleifGuest.all.map above resulted in 3cleanup_jobs, it would logEnqueued 3 jobs to Async (3 GuestsCleanupJob) (assuming all were enqueued).
The return value ofperform_all_later isnil. Note that this is differentfromperform_later, which returns the instance of the queued job class.
8.1. Enqueue Multiple Active Job Classes
Withperform_all_later, it's also possible to enqueue different Active Jobclass instances in the same call. For example:
classExportDataJob<ApplicationJobdefperform(*args)# Export dataendendclassNotifyGuestsJob<ApplicationJobdefperform(*guests)# Email guestsendend# Instantiate job instancescleanup_job=GuestsCleanupJob.new(guest)export_job=ExportDataJob.new(data)notify_job=NotifyGuestsJob.new(guest)# Enqueues job instances from multiple classes at onceActiveJob.perform_all_later(cleanup_job,export_job,notify_job)8.2. Bulk Enqueue Callbacks
When enqueuing jobs in bulk usingperform_all_later, callbacks such asaround_enqueue will not be triggered on the individual jobs. This behavior isin line with other Active Record bulk methods. Since callbacks run on individualjobs, they can't take advantage of the bulk nature of this method.
However, theperform_all_later method does fire anenqueue_all.active_jobevent which you can subscribe to usingActiveSupport::Notifications.
The methodsuccessfully_enqueued?can be used to find out if a given job was successfully enqueued.
8.3. Queue Backend Support
Forperform_all_later, bulk enqueuing needs to be backed by the queue backend.Solid Queue, the default queue backend, supports bulk enqueuing usingenqueue_all.
Other backends like Sidekiq have apush_bulkmethod, which can push a large number of jobs to Redis and prevent the roundtrip network latency. GoodJob also supports bulk enqueuing with theGoodJob::Bulk.enqueue method.
If the queue backend doesnot support bulk enqueuing,perform_all_later willenqueue jobs one by one.
9. Action Mailer
One of the most common jobs in a modern web application is sending emailsoutside of the request-response cycle, so the user doesn't have to wait on it.Active Job is integrated with Action Mailer so you can easily send emailsasynchronously:
# If you want to send the email now use #deliver_nowUserMailer.welcome(@user).deliver_now# If you want to send the email through Active Job use #deliver_laterUserMailer.welcome(@user).deliver_laterUsing the asynchronous queue from a Rake task (for example, to send anemail using.deliver_later) will generally not work because Rake will likelyend, causing the in-process thread pool to be deleted, before any/all of the.deliver_later emails are processed. To avoid this problem, use.deliver_nowor run a persistent queue in development.
10. Internationalization
Each job uses theI18n.locale set when the job was created. This is useful ifyou send emails asynchronously:
I18n.locale=:eoUserMailer.welcome(@user).deliver_later# Email will be localized to Esperanto.11. Supported Types for Arguments
ActiveJob supports the following types of arguments by default:
- Basic types (
NilClass,String,Integer,Float,BigDecimal,TrueClass,FalseClass) SymbolDateTimeDateTimeActiveSupport::TimeWithZoneActiveSupport::DurationHash(Keys should be ofStringorSymboltype)ActiveSupport::HashWithIndifferentAccessArrayRangeModuleClass
11.1. GlobalID
Active Job supportsGlobalID forparameters. This makes it possible to pass live Active Record objects to yourjob instead of class/id pairs, which you then have to manually deserialize.Before, jobs would look like this:
classTrashableCleanupJob<ApplicationJobdefperform(trashable_class,trashable_id,depth)trashable=trashable_class.constantize.find(trashable_id)trashable.cleanup(depth)endendNow you can simply do:
classTrashableCleanupJob<ApplicationJobdefperform(trashable,depth)trashable.cleanup(depth)endendThis works with any class that mixes inGlobalID::Identification, which bydefault has been mixed into Active Record classes.
11.2. Serializers
You can extend the list of supported argument types. You just need to defineyour own serializer:
# app/serializers/money_serializer.rbclassMoneySerializer<ActiveJob::Serializers::ObjectSerializer# Converts an object to a simpler representative using supported object types.# The recommended representative is a Hash with a specific key. Keys can be of basic types only.# You should call `super` to add the custom serializer type to the hash.defserialize(money)super("amount"=>money.amount,"currency"=>money.currency)end# Converts serialized value into a proper object.defdeserialize(hash)Money.new(hash["amount"],hash["currency"])endprivate# Checks if an argument should be serialized by this serializer.defklassMoneyendendand add this serializer to the list:
# config/initializers/custom_serializers.rbRails.application.config.active_job.custom_serializers<<MoneySerializerNote that autoloading reloadable code during initialization is not supported.Thus it is recommended to set-up serializers to be loaded only once, e.g. byamendingconfig/application.rb like this:
# config/application.rbmoduleYourAppclassApplication<Rails::Applicationconfig.autoload_once_paths<<"#{root}/app/serializers"endend12. Exceptions
Exceptions raised during the execution of the job can be handled withrescue_from:
classGuestsCleanupJob<ApplicationJobqueue_as:defaultrescue_from(ActiveRecord::RecordNotFound)do|exception|# Do something with the exceptionenddefperform# Do something laterendendIf an exception from a job is not rescued, then the job is referred to as"failed".
12.1. Retrying or Discarding Failed Jobs
A failed job will not be retried, unless configured otherwise.
It's possible to retry or discard a failed job by usingretry_on ordiscard_on, respectively. For example:
classRemoteServiceJob<ApplicationJobretry_onCustomAppException# defaults to 3s wait, 5 attemptsdiscard_onActiveJob::DeserializationErrordefperform(*args)# Might raise CustomAppException or ActiveJob::DeserializationErrorendend12.2. Deserialization
GlobalID allows serializing full Active Record objects passed to#perform.
If a passed record is deleted after the job is enqueued but before the#perform method is called Active Job will raise anActiveJob::DeserializationError exception.
13. Job Testing
You can find detailed instructions on how to test your jobs in thetestingguide.
14. Debugging
If you need help figuring out where jobs are coming from, you can enableverbose logging.
15. Alternate Queuing Backends
Active Job has other built-in adapters for multiple queuing backends (Sidekiq,Resque, Delayed Job, and others). To get an up-to-date list of the adapters seethe API Documentation forActiveJob::QueueAdapters.
15.1. Configuring the Backend
You can change your queuing backend withconfig.active_job.queue_adapter:
# config/application.rbmoduleYourAppclassApplication<Rails::Application# 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=:sidekiqendendYou can also configure your backend on a per job basis:
classGuestsCleanupJob<ApplicationJobself.queue_adapter=:resque# ...end# Now your job will use `resque` as its backend queue adapter, overriding the default Solid Queue adapter.15.2. Starting the Backend
Since jobs run in parallel to your Rails application, most queuing librariesrequire that you start a library-specific queuing service (in addition tostarting your Rails app) for the job processing to work. Refer to librarydocumentation for instructions on starting your queue backend.
Here is a noncomprehensive list of documentation: