Automatically retry failed ActiveJobs with an exponential back-off.
This gem aims to mimic most of the functionality of Sidekiq's RetryJobs middleware but operates on
the ActiveJob layer.
To install the gem, add the following to your Gemfile:
gem "activejob-retriable"If you're using Rails 5, use the branch master off Github for support. Once the first stable release of Rails 5 is out we will push a 5.0 version of gem.
gem "activejob-retriable", github: "SimplyBuilt/activejob-retriable"The simplest way to use this gem is to include the following your
ApplicationJob class
class ApplicationJob < ActiveJob::Base
include ActiveJob::Retriable
endA max_retry class method as well as before, after and around exception callbacks
will now be available to all your Jobs. For example:
class MyJob < ApplicationJob
max_retry 12
after_exception do
# Record exeception to our fictitious error service
ErrorNotify.dispatch current_exception
end
endBackends that support the retrying of jobs are supported. A Runtime exception is raised if this concern is included in a job class with an unsupported backend.
The gem has only been tested with the Sidekiq backend. Please submit pull-requests and issues for backends that do not function properly.
The motivation of this gem is to play nicely with existing rescue_from
blocks within your job classes. If a rescue_from block makes calls to
retry_job is it probably best to call this method if and only if
retries_exhausted? is not true. Otherwise, your jobs may be retried
indefinitely! See this test job
class
for an example.
Much like ActiveJob itself, retriable introduces some callbacks for
exception handling. Your job class can define before_exception,
after_exception and around_exception callbacks.
Retriable will also set the value of current_exception to the actual
exception. This way, direct access to the exception is possible from
within a callback. This may be useful for error reporting and other
needs.
If you want ActionMailer delivery jobs to use Retriable, you have to
reopen the ActionMailer::DeliveryJob class and manually include the
concern. For example:
module ActionMailer
class DeliveryJob
include ActiveJob::Retriable
end
endIt is recommended to do this via an initializer. We're open to
suggestions on how to improve this aspect of Retriable though!
It is possible to overload or redefine both retry_delay and
retries_exhausted? to include custom logic. This means it is easy to
implement different back-off strategies as well as more advanced
exhausted logic.
Feel free to open PR's with more advanced examples!
The default ActiveJob::QueueAdapters::TestAdapter does not call
serialize and deserialize as one may expect. Thus, retry_attempts are
not properly tracked and "infinite performs" occur when an exception is
raised. Therefore, we provided a new subclass to TestAdapter named
ActiveJob::Retriable::TestAdapter. To use this adapter please do the
following:
- Include the
ActiveJob::Retriable::TestHelperin yourtest_helper.rb
require 'active_job/retriable/test_helper'- Reopen
ActiveJob::TestCaseand include the helper
class ActiveJob::TestCase
include ActiveJob::Retriable::TestHelper
endAlternatively, you can just include the helper on a test-by-test basis.
-
If you're using ActiveJob assertions in controllers or elsewhere, be sure to include the test helper concern there as well!
-
Optionally add a setup and teardown block to toggle on
reraise_when_retry_exhausted,print_exceptions_to_stderrandprint_exception_backtraces_to_stderr. These features are useful when testing and debugging Active Jobs that raise exceptions or have syntax errors.
setup do
ActiveJob::Retriable.reraise_when_retry_exhausted = true
ActiveJob::Retriable.print_exceptions_to_stderr = true
# Or with a full backtrace...
# ActiveJob::Retriable.print_exceptions_to_stderr = :backtrace
end
teardown do
ActiveJob::Retriable.reraise_when_retry_exhausted = false
ActiveJob::Retriable.print_exceptions_to_stderr = false
endAdditionally, if you have jobs being enqueued in your setup blocks, it
is highly recommended that you move that functionality to an
after_setup method. This is due to how the default TestHelper works
and may change in the future.
- With Sidekiq, we highly encourage that you remove the RetryJobs middleware. This can be done in an initializer with the following:
Sidekiq.configure_server do |config|
config.server_middleware.remove Sidekiq::Middleware::Server::RetryJobs
endThis project rocks and uses MIT-LICENSE.