Search code examples
ruby-on-railsruby-on-rails-6rails-activejob

How do I make Active Job retry all jobs forever?


I don't want active job to drop jobs when they fail. I want to have a chance to fix the failure and then let them re-run. I tried doing this:

class ApplicationJob < ActiveJob::Base
  retry_on Exception, attempts: Float::INFINITY
end

but it didn't work. An email job failed and was just discarded. I'm using delayed_job as the implementation.

Any ideas how to do it?


Solution

  • If you are using Delayed::Job, you end up with two retrying mechanisms on top of each other. Active Job, the Rails general implementation, and the Delayed::Job.

    For Active::Job you can do:

    class ApplicationJob < ActiveJob::Base
      retry_on Exception, wait: :exponentially_longer, attempts: Float::INFINITY
    end
    

    Without the wait: :exponentially_longer, you may end up with a lot of jobs trying every 3 seconds.

    The behavior of this retrying method can be a bit odd if you are using Delayed::Job. The job runs and seems to succeed but since it fails, ActiveJob creates a new one to run at a later time. Because of that the field attempts in Delayed::Job remains at 0 and you need to look at the field handler to see how many times it was run.

    One ActiveJob fails for the last time, the exception bubbles up to Delayed::Job which has its own retrying mechanism. Delayed::Job by default retries 25 times and then deletes the job.

    To make Delayed Job keep on trying forever, you can create an initialization file config/initializers/delayed_job_config.rb changing the max_attempts values:

    Delayed::Worker.max_attempts = Float::INFINITY
    

    If you are worried about losing jobs though, the jobs can fail and not be removed by setting:

    Delayed::Worker.destroy_failed_jobs = false
    

    which of the two you use, or how you mix them is up to you. Using Delayed::Job's makes the database make a bit more sense, using ActiveJob's means the method can be transported to other implementations.