diff --git a/activejob/lib/active_job/exceptions.rb b/activejob/lib/active_job/exceptions.rb index f60240fe54..c7d0330359 100644 --- a/activejob/lib/active_job/exceptions.rb +++ b/activejob/lib/active_job/exceptions.rb @@ -7,6 +7,11 @@ module ActiveJob module Exceptions extend ActiveSupport::Concern + included do + class_attribute :default_retry_jitter, instance_accessor: false, instance_predicate: false + self.default_retry_jitter = 0.15 + end + module ClassMethods # Catch the exception and reschedule job for re-execution after so many seconds, for a specific number of attempts. # If the exception keeps getting raised beyond the specified number of attempts, the exception is allowed to @@ -49,7 +54,7 @@ module ActiveJob # # Might raise Net::OpenTimeout or Timeout::Error when the remote service is down # end # end - def retry_on(*exceptions, wait: 3.seconds, attempts: 5, queue: nil, priority: nil, jitter: 0.15) + def retry_on(*exceptions, wait: 3.seconds, attempts: 5, queue: nil, priority: nil, jitter: nil) rescue_from(*exceptions) do |error| executions = executions_for(exceptions) if executions < attempts @@ -122,7 +127,8 @@ module ActiveJob end private - def determine_delay(seconds_or_duration_or_algorithm:, executions:, jitter:) + def determine_delay(seconds_or_duration_or_algorithm:, executions:, jitter: nil) + jitter ||= self.class.default_retry_jitter case seconds_or_duration_or_algorithm when :exponentially_longer ((executions**4) + (Kernel.rand((executions**4) * jitter))) + 2 diff --git a/activejob/test/cases/exceptions_test.rb b/activejob/test/cases/exceptions_test.rb index 277016c9d2..96f3babadd 100644 --- a/activejob/test/cases/exceptions_test.rb +++ b/activejob/test/cases/exceptions_test.rb @@ -129,6 +129,31 @@ class ExceptionsTest < ActiveSupport::TestCase end end + test "retry jitter uses value from ActiveJob::Base.default_retry_jitter by default" do + old_jitter = ActiveJob::Base.default_retry_jitter + ActiveJob::Base.default_retry_jitter = 4.0 + + travel_to Time.now + + Kernel.stub(:rand, ->(arg) { arg }) do + RetryJob.perform_later "ExponentialWaitTenAttemptsError", 5, :log_scheduled_at + + assert_equal [ + "Raised ExponentialWaitTenAttemptsError for the 1st time", + "Next execution scheduled at #{(Time.now + 7.seconds).to_f}", + "Raised ExponentialWaitTenAttemptsError for the 2nd time", + "Next execution scheduled at #{(Time.now + 82.seconds).to_f}", + "Raised ExponentialWaitTenAttemptsError for the 3rd time", + "Next execution scheduled at #{(Time.now + 407.seconds).to_f}", + "Raised ExponentialWaitTenAttemptsError for the 4th time", + "Next execution scheduled at #{(Time.now + 1282.seconds).to_f}", + "Successfully completed job" + ], JobBuffer.values + end + ensure + ActiveJob::Base.default_retry_jitter = old_jitter + end + test "custom wait retrying job" do travel_to Time.now diff --git a/railties/lib/rails/application/configuration.rb b/railties/lib/rails/application/configuration.rb index d57a86006d..317bdea388 100644 --- a/railties/lib/rails/application/configuration.rb +++ b/railties/lib/rails/application/configuration.rb @@ -156,6 +156,10 @@ module Rails when "6.1" load_defaults "6.0" + if respond_to?(:active_job) + active_job.default_retry_jitter = 0.15 + end + if respond_to?(:active_record) active_record.has_many_inversing = true end diff --git a/railties/test/application/configuration_test.rb b/railties/test/application/configuration_test.rb index 7084185a33..aee9fb7ae4 100644 --- a/railties/test/application/configuration_test.rb +++ b/railties/test/application/configuration_test.rb @@ -2262,6 +2262,20 @@ module ApplicationTests end end + test "ActiveJob::Base.default_retry_jitter is 0.15 by default" do + app "development" + + assert_equal 0.15, ActiveJob::Base.default_retry_jitter + end + + test "ActiveJob::Base.default_retry_jitter can be set by config" do + app "development" + + Rails.application.config.active_job.default_retry_jitter = 0.22 + + assert_equal 0.22, ActiveJob::Base.default_retry_jitter + end + test "ActiveJob::Base.return_false_on_aborted_enqueue is true by default" do app "development"