Skip to content


Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Match exception instance against retry_exceptions

This allows to 'tag' exceptions with a module instead of having to
wrap them in custom exception classes, which is useful when you want
to keep the original exception for logging and diagnosis after the
retry limit was exceeded. Using the === operator makes the matching
work the same as the ruby rescue clause.


module TransientError; end

def foo
rescue Timeout::Error => e
  raise e.extend(TransientError)

class SomeJob
  def self.retry_exceptions

The old behaviour of the public method retry_exception? so that you
can alternatively pass an exception class instead of an exception
instance to it is kept but documented as deprecated.

This is a reworked version of this commit:

  • Loading branch information...
commit 7938de50862fd336fb15e616ec1afc9a2f2d1d69 1 parent e6e57b8
@til til authored
16 lib/resque/plugins/retry.rb
@@ -140,14 +140,24 @@ def args_for_retry(*args)
- # Convenience method to test whether you may retry on a given exception
+ # Convenience method to test whether you may retry on a given
+ # exception
+ #
+ # @param [Exception] an instance of Exception. Deprecated: can
+ # also be a Class
# @return [Boolean]
# @api public
def retry_exception?(exception)
return true if retry_exceptions.nil?
- !! retry_exceptions.any? { |ex| ex >= exception }
+ !! retry_exceptions.any? do |ex|
+ if exception.is_a?(Class)
+ ex >= exception
+ else
+ ex === exception
+ end
+ end
# @abstract
@@ -178,7 +188,7 @@ def retry_criteria_valid?(exception, *args)
return false if retry_limit_reached?
# We always want to retry if the exception matches.
- should_retry = retry_exception?(exception.class)
+ should_retry = retry_exception?(exception)
# call user retry criteria check blocks.
retry_criteria_checks.each do |criteria_check|
17 test/retry_test.rb
@@ -108,13 +108,17 @@ def test_retry_delay_sleep
assert_equal 0,[:pending], 'pending jobs'
- def test_can_determine_if_exception_may_be_retried
+ def test_can_determine_if_exception_may_be_retried_with_defaults
assert_equal true, RetryDefaultsJob.retry_exception?(StandardError), 'StandardError may retry'
assert_equal true, RetryDefaultsJob.retry_exception?(CustomException), 'CustomException may retry'
assert_equal true, RetryDefaultsJob.retry_exception?(HierarchyCustomException), 'HierarchyCustomException may retry'
+ end
+ def test_can_determine_if_exception_may_be_retried_with_custom_retry_exceptions
+ assert_equal false, RetryCustomExceptionsJob.retry_exception?(StandardError), 'StandardError may not retry'
assert_equal true, RetryCustomExceptionsJob.retry_exception?(CustomException), 'CustomException may retry'
assert_equal true, RetryCustomExceptionsJob.retry_exception?(HierarchyCustomException), 'HierarchyCustomException may retry'
+ assert_equal true, RetryCustomExceptionsJob.retry_exception?(, 'Extended with CustomExceptionModule may retry'
assert_equal false, RetryCustomExceptionsJob.retry_exception?(AnotherCustomException), 'AnotherCustomException may not retry'
@@ -130,6 +134,17 @@ def test_retry_if_failed_and_exception_may_retry
assert_equal 2,[:pending], 'pending jobs'
+ def test_retry_if_failed_and_exception_may_retry_because_of_included_module
+ Resque.enqueue(RetryCustomExceptionsJob, 'tagged CustomException')
+ 4.times do
+ perform_next_job(@worker)
+ end
+ assert_equal 4,[:failed], 'failed jobs'
+ assert_equal 4,[:processed], 'processed job'
+ assert_equal 1,[:pending], 'pending jobs'
+ end
def test_do_not_retry_if_failed_and_exception_does_not_allow_retry
Resque.enqueue(RetryCustomExceptionsJob, AnotherCustomException)
Resque.enqueue(RetryCustomExceptionsJob, RuntimeError)
4 test/test_jobs.rb
@@ -1,4 +1,5 @@
CustomException =
+CustomExceptionModule =
HierarchyCustomException =
AnotherCustomException =
@@ -155,12 +156,13 @@ class RetryCustomExceptionsJob < RetryDefaultsJob
@queue = :testing
@retry_limit = 5
- @retry_exceptions = [CustomException, HierarchyCustomException]
+ @retry_exceptions = [CustomException, CustomExceptionModule, HierarchyCustomException]
def self.perform(exception)
case exception
when 'CustomException' then raise CustomException
when 'HierarchyCustomException' then raise HierarchyCustomException
+ when 'tagged CustomException' then raise
when 'AnotherCustomException' then raise AnotherCustomException
else raise StandardError
Please sign in to comment.
Something went wrong with that request. Please try again.