Before Rails 6
Before Rails 6, we have to provide a custom block to perform custom logging and monitoring around retries and discards of the jobs defined using Active Job framework.
Notice the custom blocks provided
to an individual job
in the above example.
Extracting such custom logic to a base class or to a 3rd-party gem is possible but it will be non-standard and will be a bit difficult task.
An alternative approach is
to the hooks instrumented using Active Support Instrumentation API
which is a standard and recommended way.
Prior versions of Rails 6 already instruments
Unfortunately no hook is instrumented
around retries and discards of an Active Job
prior to Rails 6.
Rails 6 has introduced hooks to Active Job around retries and discards to which one can easily subscribe using Active Support Instrumentation API to perform custom logging and monitoring or to collect any custom information.
The newly introduced hooks are
Let’s discuss each of these hooks in detail.
Note that whenever we say
it means a job of type
instrumented when a job
enqueued to retry again
due to occurrence of an exception which
is configured using the
in the job’s definition.
This hook is triggered
only when above condition is satisfied
the number of executions of the job
less than the number of
defined using the
The number of
attempts is by default set to 5
if not defined explicitly.
This is how we would subscribe to this hook and perform custom logging in our Rails application.
Note that the
BackgroundJob::Logger above is our custom logger.
If we want, we can add any other logic instead.
We will change the definition of
Container::DeleteJob job as below.
Let’s enqueue this job.
Assume that this job keeps throwing
due to a network issue.
The job will be retried twice
since it is configured to retry
Timeout::Error exception occurs
up to maximum 3 attempts.
While retrying this job,
Active Job will instrument
along with the necessary job payload.
Since we have already subscribed to this hook,
our subscriber would log something like this
with the help of
retry_stopped.active_job hook is triggered
when a job is retried
up to the available number of
Let’s see how this hook is triggered.
Along with the subscription for the
let’s subscribe to the
retry_stopped.active_job hook, too.
Let’s keep the
Container::DeleteJob job’s definition unchanged
and enqueue it again.
We will assume that the job will keep throwing
due to a network issue.
In the logs recorded using
we should see something like this.
Notice the last entry in the logs above and its order.
discard.active_job hook is triggered
when a job’s further execution is discarded
due to occurrence of an exception
which is configured using
To see how this hook is triggered,
we will subscribe to the
We will configure our
Container::NotFoundError exception occurs
while executing the job.
Let’s enqueue this job
assume that it would throw
We should see following in the logs recorded by
These new hooks are also instrumented for the jobs which are enqueued using
perform_latermethod since both
performmethod under the hood.
Active Job already subscribes to the these hooks and writes them using the Rails’ default logger.
If a block is provided to
discard_onmethods then an applicable hook is instrumented first and then the given block is yielded.