Module: Resque::Plugins::ExponentialBackoff

Includes:
Retry
Defined in:
lib/resque/plugins/exponential_backoff.rb

Overview

If you want your job to retry on failure using a varying delay, simply extend your module/class with this module:

class DeliverSMS
  extend Resque::Plugins::ExponentialBackoff
  @queue = :mt_messages

  def self.perform(mt_id, mobile_number, message)
    heavy_lifting
  end
end

Easily do something custom:

class DeliverSMS
  extend Resque::Plugins::ExponentialBackoff
  @queue = :mt_messages

  @retry_limit = 4

  # retry delay in seconds; [0] => 1st retry, [1] => 2nd..4th retry.
  @backoff_strategy = [0, 60]

  # used to build redis key, for counting job attempts.
  def self.retry_identifier(mt_id, mobile_number, message)
    "#{mobile_number}:#{mt_id}"
  end

  self.perform(mt_id, mobile_number, message)
    heavy_lifting
  end
end

Defined Under Namespace

Classes: InvalidRetryDelayMultiplicandConfigurationException

Constant Summary collapse

DEFAULT_RETRY_DELAY_MULTIPLICAND_MIN =

Constants

1.0
DEFAULT_RETRY_DELAY_MULTIPLICAND_MAX =
1.0

Instance Attribute Summary

Attributes included from Retry

#expire_retry_key_after, #fatal_exceptions

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Retry

#after_perform_retry, #before_perform_retry, #call_symbol_or_block, #clean_retry_key, #give_up, #give_up_callback, #give_up_callbacks, #ignore_exceptions, #inherited, #instance_exec, #on_failure_retry, #redis_retry_key, #retry_args, #retry_args_for_exception, #retry_attempt, #retry_criteria_check, #retry_criteria_checks, #retry_criteria_checks_pass?, #retry_criteria_valid?, #retry_exception?, #retry_exceptions, #retry_identifier, #retry_job_delegate, #retry_limit_reached?, #retry_queue, #run_give_up_callbacks, #run_try_again_callbacks, #sleep_after_requeue, #try_again, #try_again_callback, #try_again_callbacks

Methods included from Retry::Logging

#log_message

Class Method Details

.extended(receiver) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Fail fast, when extended, if the “receiver” is misconfigured



54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/resque/plugins/exponential_backoff.rb', line 54

def self.extended(receiver)
  retry_delay_multiplicand_min = DEFAULT_RETRY_DELAY_MULTIPLICAND_MIN
  retry_delay_multiplicand_min = \
    receiver.instance_variable_get(:@retry_delay_multiplicand_min) \
      if receiver.instance_variable_defined?(:@retry_delay_multiplicand_min)

  retry_delay_multiplicand_max = DEFAULT_RETRY_DELAY_MULTIPLICAND_MAX
  retry_delay_multiplicand_max = \
    receiver.instance_variable_get(:@retry_delay_multiplicand_max) \
      if receiver.instance_variable_defined?(:@retry_delay_multiplicand_max)

  if retry_delay_multiplicand_min > retry_delay_multiplicand_max
    raise InvalidRetryDelayMultiplicandConfigurationException.new(
      %{"@retry_delay_multiplicand_min" must be less than or equal to "@retry_delay_multiplicand_max"}
    )
  end
end

Instance Method Details

#backoff_strategyArray

This method is abstract.

The backoff strategy is used to vary the delay between retry attempts

Returns:

  • (Array)

    array of delays. index = retry attempt



128
129
130
# File 'lib/resque/plugins/exponential_backoff.rb', line 128

def backoff_strategy
  @backoff_strategy ||= [0, 60, 600, 3600, 10_800, 21_600]
end

#retry_delay(_ = nil) ⇒ Number

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Selects the delay from the backoff strategy

Parameters:

  • _ (Exception) (defaults to: nil)

    unused exception argument for signature parity

Returns:

  • (Number)

    seconds to delay until the next retry.



87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/resque/plugins/exponential_backoff.rb', line 87

def retry_delay(_ = nil)
  delay = backoff_strategy[retry_attempt] || backoff_strategy.last
  # if the values are the same don't bother generating a random number, if
  # the delta is zero, some platforms will raise an error
  if retry_delay_multiplicand_min == retry_delay_multiplicand_max
    delay_multiplicand = retry_delay_multiplicand_max
  else
    delay_multiplicand = \
      rand(retry_delay_multiplicand_min..retry_delay_multiplicand_max)
  end
  (delay * delay_multiplicand).to_i
end

#retry_delay_multiplicand_maxFloat

This method is abstract.

The maximum value (upper-bound) for the range that is is used in calculating the retry-delay product

Returns:

  • (Float)


118
119
120
# File 'lib/resque/plugins/exponential_backoff.rb', line 118

def retry_delay_multiplicand_max
  @retry_delay_multiplicand_max ||= DEFAULT_RETRY_DELAY_MULTIPLICAND_MAX
end

#retry_delay_multiplicand_minFloat

This method is abstract.

The minimum value (lower-bound) for the range that is is used in calculating the retry-delay product

Returns:

  • (Float)


107
108
109
# File 'lib/resque/plugins/exponential_backoff.rb', line 107

def retry_delay_multiplicand_min
  @retry_delay_multiplicand_min ||= DEFAULT_RETRY_DELAY_MULTIPLICAND_MIN
end

#retry_limitNumber

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Defaults to the number of delays in the backoff strategy

Returns:

  • (Number)

    maximum number of retries



77
78
79
# File 'lib/resque/plugins/exponential_backoff.rb', line 77

def retry_limit
  @retry_limit ||= backoff_strategy.length
end