1
0
Fork 0
mirror of https://github.com/mperham/sidekiq.git synced 2022-11-09 13:52:34 -05:00

use 'retry' option to customize max retry attempts

e.g.
{ 'class' => 'HardWorker', 'args' => [1, 2, 'foo'], 'retry' => 5 }

Addresses Issue #313
This commit is contained in:
Noah Davis 2012-10-17 18:51:26 -04:00
parent fc3a1fdc50
commit bc1e38f85a
2 changed files with 51 additions and 3 deletions

View file

@ -20,6 +20,13 @@ module Sidekiq
#
# { 'class' => 'HardWorker', 'args' => [1, 2, 'foo'] }
#
# The 'retry' option also accepts a number (in place of 'true'):
#
# { 'class' => 'HardWorker', 'args' => [1, 2, 'foo'], 'retry' => 5 }
#
# The job will be retried this number of times before giving up. (If simply
# 'true', Sidekiq retries 25 times)
#
# We'll add a bit more data to the message to support retries:
#
# * 'queue' - the queue to use
@ -35,13 +42,14 @@ module Sidekiq
include Sidekiq::Util
# delayed_job uses the same basic formula
MAX_COUNT = 25
DEFAULT_MAX_RETRY_ATTEMPTS = 25
DELAY = proc { |count| (count ** 4) + 15 }
def call(worker, msg, queue)
yield
rescue Exception => e
raise e unless msg['retry']
max_retry_attempts = retry_attempts_from(msg['retry'], DEFAULT_MAX_RETRY_ATTEMPTS)
msg['queue'] = queue
msg['error_message'] = e.message
@ -60,7 +68,7 @@ module Sidekiq
msg['error_backtrace'] = e.backtrace[0..msg['backtrace'].to_i]
end
if count <= MAX_COUNT
if count <= max_retry_attempts
delay = DELAY.call(count)
logger.debug { "Failure! Retry #{count} in #{delay} seconds" }
retry_at = Time.now.to_f + delay
@ -75,6 +83,14 @@ module Sidekiq
raise e
end
def retry_attempts_from(msg_retry, default)
if msg_retry.is_a?(Fixnum)
msg_retry
else
default
end
end
end
end
end

View file

@ -88,7 +88,25 @@ class TestRetry < MiniTest::Unit::TestCase
@redis.verify
end
it 'throws away old messages after too many retries' do
it 'handles a recurring failed message before reaching user-specifed max' do
@redis.expect :zadd, 1, ['retry', String, String]
now = Time.now.utc
msg = {"class"=>"Bob", "args"=>[1, 2, "foo"], 'retry' => 11, "queue"=>"default", "error_message"=>"kerblammo!", "error_class"=>"RuntimeError", "failed_at"=>now, "retry_count"=>10}
handler = Sidekiq::Middleware::Server::RetryJobs.new
assert_raises RuntimeError do
handler.call('', msg, 'default') do
raise "kerblammo!"
end
end
assert_equal 'default', msg["queue"]
assert_equal 'kerblammo!', msg["error_message"]
assert_equal 'RuntimeError', msg["error_class"]
assert_equal 11, msg["retry_count"]
assert msg["failed_at"]
@redis.verify
end
it 'throws away old messages after too many retries (using the default)' do
now = Time.now.utc
msg = {"class"=>"Bob", "args"=>[1, 2, "foo"], "queue"=>"default", "error_message"=>"kerblammo!", "error_class"=>"RuntimeError", "failed_at"=>now, "retry"=>true, "retry_count"=>25}
@redis.expect :zadd, 1, [ 'retry', String, String ]
@ -101,6 +119,20 @@ class TestRetry < MiniTest::Unit::TestCase
# MiniTest can't assert that a method call did NOT happen!?
assert_raises(MockExpectationError) { @redis.verify }
end
it 'throws away old messages after too many retries (using user-specified max)' do
now = Time.now.utc
msg = {"class"=>"Bob", "args"=>[1, 2, "foo"], "queue"=>"default", "error_message"=>"kerblammo!", "error_class"=>"RuntimeError", "failed_at"=>now, "retry"=>3, "retry_count"=>3}
@redis.expect :zadd, 1, [ 'retry', String, String ]
handler = Sidekiq::Middleware::Server::RetryJobs.new
assert_raises RuntimeError do
handler.call('', msg, 'default') do
raise "kerblammo!"
end
end
# MiniTest can't assert that a method call did NOT happen!?
assert_raises(MockExpectationError) { @redis.verify }
end
end
describe 'poller' do