diff --git a/lib/sidekiq/middleware/server/retry_jobs.rb b/lib/sidekiq/middleware/server/retry_jobs.rb index 1bc82167..bdb81d0b 100644 --- a/lib/sidekiq/middleware/server/retry_jobs.rb +++ b/lib/sidekiq/middleware/server/retry_jobs.rb @@ -83,13 +83,20 @@ module Sidekiq end else # Goodbye dear message, you (re)tried your best I'm sure. - worker.exhausted(*msg['args']) if worker.respond_to?(:exhausted) - logger.debug { "Dropping message after hitting the retry maximum: #{msg}" } + retries_exhausted(msg) end raise e end + def retries_exhausted(msg) + logger.debug { "Dropping message after hitting the retry maximum: #{msg}" } + worker.retries_exhausted(*msg['args']) if worker.respond_to?(:retries_exhausted) + + rescue Exception => e + logger.debug { "Failure during `retries_exhausted` hook: #{e} - #{msg}" } + end + def retry_attempts_from(msg_retry, default) if msg_retry.is_a?(Fixnum) msg_retry diff --git a/test/test_retry.rb b/test/test_retry.rb index 4546544b..e1f293b4 100644 --- a/test/test_retry.rb +++ b/test/test_retry.rb @@ -168,14 +168,30 @@ class TestRetry < MiniTest::Unit::TestCase assert_raises(MockExpectationError) { @redis.verify } end - it 'calls exhausted method on worker after too many retries if available' do - msg = {"class"=>"Bob", "args"=>[1, 2, "foo"], "queue"=>"default", "error_message"=>"kerblammo!", "error_class"=>"RuntimeError", "failed_at"=>Time.now.utc, "retry"=>3, "retry_count"=>3} - worker = MiniTest::Mock.new - worker.expect :exhausted, true, [1, 2, "foo"] - handler = Sidekiq::Middleware::Server::RetryJobs.new - assert_raises RuntimeError do - handler.call(worker, msg, 'default') do - raise "kerblammo!" + describe "retry exhaustion" do + let(:worker){ MiniTest::Mock.new } + let(:handler){ Sidekiq::Middleware::Server::RetryJobs.new } + let(:msg){ {"class"=>"Bob", "args"=>[1, 2, "foo"], "queue"=>"default", "error_message"=>"kerblammo!", "error_class"=>"RuntimeError", "failed_at"=>Time.now.utc, "retry"=>3, "retry_count"=>3} } + + it 'calls worker retries_exhausted after too many retries' do + worker.expect(:retries_exhausted, true, [1,2,3]) + task_misbehaving_worker + end + + it 'handles and logs retries_exhausted failures gracefully (drops them)' do + def worker.retries_exhausted(*args) + raise 'bam!' + end + + e = task_misbehaving_worker + assert_equal e.message, "kerblammo!" + end + + def task_misbehaving_worker + assert_raises RuntimeError do + handler.call('', msg, 'default') do + raise 'kerblammo!' + end end end end