Merge pull request #6153 from betagouv/retry-active-storage-jobs-on-transient-error
Les jobs ActiveStorage et ApplicationJob ré-essaient automatiquement plus tard en cas d'erreur réseau (#6153)
This commit is contained in:
commit
aae5f3f0db
7 changed files with 68 additions and 18 deletions
|
@ -1,7 +1,7 @@
|
||||||
class ApplicationJob < ActiveJob::Base
|
class ApplicationJob < ActiveJob::Base
|
||||||
DEFAULT_MAX_ATTEMPTS_JOBS = 25
|
include ActiveJob::RetryOnTransientErrors
|
||||||
|
|
||||||
retry_on ::Excon::Error::BadRequest
|
DEFAULT_MAX_ATTEMPTS_JOBS = 25
|
||||||
|
|
||||||
before_perform do |job|
|
before_perform do |job|
|
||||||
Rails.logger.info("#{job.class.name} started at #{Time.zone.now}")
|
Rails.logger.info("#{job.class.name} started at #{Time.zone.now}")
|
||||||
|
|
17
app/lib/active_job/retry_on_transient_errors.rb
Normal file
17
app/lib/active_job/retry_on_transient_errors.rb
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
module ActiveJob::RetryOnTransientErrors
|
||||||
|
extend ActiveSupport::Concern
|
||||||
|
|
||||||
|
TRANSIENT_ERRORS = [
|
||||||
|
Excon::Error::InternalServerError,
|
||||||
|
Excon::Error::GatewayTimeout,
|
||||||
|
Excon::Error::BadRequest
|
||||||
|
]
|
||||||
|
|
||||||
|
included do
|
||||||
|
if handler_for_rescue(TRANSIENT_ERRORS.first).nil?
|
||||||
|
TRANSIENT_ERRORS.each do |error_type|
|
||||||
|
retry_on error_type, attempts: 5, wait: :exponentially_longer
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -14,6 +14,12 @@ ActiveSupport.on_load(:active_storage_attachment) do
|
||||||
include AttachmentVirusScannerConcern
|
include AttachmentVirusScannerConcern
|
||||||
end
|
end
|
||||||
|
|
||||||
|
Rails.application.reloader.to_prepare do
|
||||||
|
class ActiveStorage::BaseJob
|
||||||
|
include ActiveJob::RetryOnTransientErrors
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# When an OpenStack service is initialized it makes a request to fetch
|
# When an OpenStack service is initialized it makes a request to fetch
|
||||||
# `publicURL` to use for all operations. We intercept the method that reads
|
# `publicURL` to use for all operations. We intercept the method that reads
|
||||||
# this url and replace the host with DS_Proxy host. This way all the operation
|
# this url and replace the host with DS_Proxy host. This way all the operation
|
||||||
|
|
3
spec/jobs/active_storage/base_job_spec.rb
Normal file
3
spec/jobs/active_storage/base_job_spec.rb
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
describe ActiveStorage::BaseJob do
|
||||||
|
it_behaves_like 'a job retrying transient errors'
|
||||||
|
end
|
|
@ -1,6 +1,8 @@
|
||||||
include ActiveJob::TestHelper
|
include ActiveJob::TestHelper
|
||||||
|
|
||||||
RSpec.describe ApplicationJob, type: :job do
|
RSpec.describe ApplicationJob, type: :job do
|
||||||
|
it_behaves_like 'a job retrying transient errors'
|
||||||
|
|
||||||
describe 'perform' do
|
describe 'perform' do
|
||||||
before do
|
before do
|
||||||
allow(Rails.logger).to receive(:info)
|
allow(Rails.logger).to receive(:info)
|
||||||
|
@ -13,23 +15,7 @@ RSpec.describe ApplicationJob, type: :job do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when ::Excon::Error::BadRequest is raised' do
|
|
||||||
# https://api.rubyonrails.org/classes/ActiveJob/Exceptions/ClassMethods.html#method-i-retry_on
|
|
||||||
# retry on will try 5 times and then bubble up the error
|
|
||||||
it 'makes 5 attempts' do
|
|
||||||
assert_performed_jobs 5 do
|
|
||||||
ExconErrJob.perform_later rescue ::Excon::Error::BadRequest
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
class ChildJob < ApplicationJob
|
class ChildJob < ApplicationJob
|
||||||
def perform; end
|
def perform; end
|
||||||
end
|
end
|
||||||
|
|
||||||
class ExconErrJob < ApplicationJob
|
|
||||||
def perform
|
|
||||||
raise ::Excon::Error::BadRequest.new('bad request')
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
9
spec/lib/active_job/retry_on_transient_errors_spec.rb
Normal file
9
spec/lib/active_job/retry_on_transient_errors_spec.rb
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
describe ActiveJob::RetryOnTransientErrors do
|
||||||
|
# rubocop:disable Rails/ApplicationJob
|
||||||
|
class Job < ActiveJob::Base
|
||||||
|
include ActiveJob::RetryOnTransientErrors
|
||||||
|
end
|
||||||
|
# rubocop:enable Rails/ApplicationJob
|
||||||
|
|
||||||
|
it_behaves_like 'a job retrying transient errors', Job
|
||||||
|
end
|
29
spec/support/shared_examples_for_jobs.rb
Normal file
29
spec/support/shared_examples_for_jobs.rb
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
RSpec.shared_examples 'a job retrying transient errors' do |job_class = described_class|
|
||||||
|
context 'when a transient network error is raised' do
|
||||||
|
ExconErrorJob = Class.new(job_class) do
|
||||||
|
def perform
|
||||||
|
raise Excon::Error::InternalServerError, 'msg'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'makes 5 attempts before raising the exception up' do
|
||||||
|
assert_performed_jobs 5 do
|
||||||
|
ExconErrorJob.perform_later rescue Excon::Error::InternalServerError
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when another type of error is raised' do
|
||||||
|
StandardErrorJob = Class.new(job_class) do
|
||||||
|
def perform
|
||||||
|
raise StandardError
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'makes only 1 attempt before raising the exception up' do
|
||||||
|
assert_performed_jobs 1 do
|
||||||
|
StandardErrorJob.perform_later rescue StandardError
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
Loading…
Add table
Add a link
Reference in a new issue