Module: Resque::Plugins::Retry

Included in:
ExponentialBackoff
Defined in:
lib/resque/plugins/retry.rb

Overview

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

class DeliverWebHook
  extend Resque::Plugins::Retry # allows 1 retry by default.
  @queue = :web_hooks

  def self.perform(url, hook_id, hmac_key)
    heavy_lifting
  end
end

Easily do something custom:

class DeliverWebHook
  extend Resque::Plugins::Retry
  @queue = :web_hooks

  @retry_limit = 8          # default: 1
  @retry_delay = 60 # default: 0

  # used to build redis key, for counting job attempts.
  def self.identifier(url, hook_id, hmac_key)
    "#{url}-#{hook_id}"
  end

  def self.perform(url, hook_id, hmac_key)
    heavy_lifting
  end
end

Instance Method Summary collapse

Instance Method Details

#after_perform_retry(*args) ⇒ Object

Resque after_perform hook.

Deletes retry attempt count from Redis.



159
160
161
# File 'lib/resque/plugins/retry.rb', line 159

def after_perform_retry(*args)
  Resque.redis.del(redis_retry_key(*args))
end

#args_for_retry(*args) ⇒ Array

This method is abstract.

Modify the arguments used to retry the job. Use this to do something other than try the exact same job again.

Returns:

  • (Array)

    new job arguments



96
97
98
# File 'lib/resque/plugins/retry.rb', line 96

def args_for_retry(*args)
  args
end

#before_perform_retry(*args) ⇒ Object

Resque before_perform hook.

Increments and sets the ‘@retry_attempt` count.



149
150
151
152
153
# File 'lib/resque/plugins/retry.rb', line 149

def before_perform_retry(*args)
  retry_key = redis_retry_key(*args)
  Resque.redis.setnx(retry_key, -1)             # default to -1 if not set.
  @retry_attempt = Resque.redis.incr(retry_key) # increment by 1.
end

#identifier(*args) ⇒ String

This method is abstract.

You may override to implement a custom identifier, you should consider doing this if your job arguments are many/long or may not cleanly cleanly to strings.

Builds an identifier using the job arguments. This identifier is used as part of the redis key.

Parameters:

  • args (Array)

    job arguments

Returns:

  • (String)

    job identifier



47
48
49
50
# File 'lib/resque/plugins/retry.rb', line 47

def identifier(*args)
  args_string = args.join('-')
  args_string.empty? ? nil : args_string
end

#on_failure_retry(exception, *args) ⇒ Object

Resque on_failure hook.

Checks if our retry criteria is valid, if it is we try again. Otherwise the retry attempt count is deleted from Redis.



168
169
170
171
172
173
174
# File 'lib/resque/plugins/retry.rb', line 168

def on_failure_retry(exception, *args)
  if retry_criteria_valid?(exception, *args)
    try_again(*args)
  else
    Resque.redis.del(redis_retry_key(*args))
  end
end

#redis_retry_key(*args) ⇒ String

Builds the redis key to be used for keeping state of the job attempts.

Returns:

  • (String)

    redis key



57
58
59
# File 'lib/resque/plugins/retry.rb', line 57

def redis_retry_key(*args)
  ['resque-retry', name, identifier(*args)].compact.join(":").gsub(/\s/, '')
end

#retry_attemptFixnum

Number of retry attempts used to try and perform the job.

The real value is kept in Redis, it is accessed and incremented using a before_perform hook.

Returns:

  • (Fixnum)

    number of attempts



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

def retry_attempt
  @retry_attempt ||= 0
end

#retry_criteria_valid?(exception, *args) ⇒ Boolean

Test if the retry criteria is valid.

Parameters:

  • exception (Exception)
  • args (Array)

    job arguments

Returns:

  • (Boolean)


126
127
128
129
130
131
132
# File 'lib/resque/plugins/retry.rb', line 126

def retry_criteria_valid?(exception, *args)
  # FIXME: let people extend retry criteria, give them a chance to say no.
  if retry_limit > 0
    return false if retry_attempt >= retry_limit
  end
  retry_exception?(exception.class)
end

#retry_delayNumber

This method is abstract.

Number of seconds to delay until the job is retried.

Returns:

  • (Number)

    number of seconds to delay



86
87
88
# File 'lib/resque/plugins/retry.rb', line 86

def retry_delay
  @retry_delay ||= 0
end

#retry_exception?(exception) ⇒ Boolean

Convenience method to test whether you may retry on a given exception.

Returns:

  • (Boolean)


104
105
106
107
# File 'lib/resque/plugins/retry.rb', line 104

def retry_exception?(exception)
  return true if retry_exceptions.nil?
  !! retry_exceptions.any? { |ex| ex >= exception }
end

#retry_exceptionsArray?

This method is abstract.

Controls what exceptions may be retried.

Default: ‘nil` - this will retry all exceptions.

Returns:

  • (Array, nil)


116
117
118
# File 'lib/resque/plugins/retry.rb', line 116

def retry_exceptions
  @retry_exceptions ||= nil
end

#retry_limitFixnum

Maximum number of retrys we can attempt to successfully perform the job. A retry limit of 0 or below will retry forever.

Returns:

  • (Fixnum)


66
67
68
# File 'lib/resque/plugins/retry.rb', line 66

def retry_limit
  @retry_limit ||= 1
end

#try_again(*args) ⇒ Object

Will retry the job.



136
137
138
139
140
141
142
143
# File 'lib/resque/plugins/retry.rb', line 136

def try_again(*args)
  if retry_delay <= 0
    # If the delay is 0, no point passing it through the scheduler
    Resque.enqueue(self, *args_for_retry(*args))
  else
    Resque.enqueue_in(retry_delay, self, *args_for_retry(*args))
  end
end