module Resque::Plugins::ExponentialBackoff

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

Constants

DEFAULT_RETRY_DELAY_MULTIPLICAND_MAX
DEFAULT_RETRY_DELAY_MULTIPLICAND_MIN

Constants

@api public

Public Class Methods

extended(receiver) click to toggle source

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

@api private

# 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

Public Instance Methods

backoff_strategy() click to toggle source

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

@return [Array] array of delays. index = retry attempt

@api public

# 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) click to toggle source

Selects the delay from the backoff strategy

@param _ [Exception] unused exception argument for signature parity @return [Number] seconds to delay until the next retry.

@api private

# 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_max() click to toggle source

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

@return [Float]

@api public

# 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_min() click to toggle source

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

@return [Float]

@api public

# 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_limit() click to toggle source

Defaults to the number of delays in the backoff strategy

@return [Number] maximum number of retries

@api private

# File lib/resque/plugins/exponential_backoff.rb, line 77
def retry_limit
  @retry_limit ||= backoff_strategy.length
end