mirror of
https://github.com/mperham/sidekiq.git
synced 2022-11-09 13:52:34 -05:00
Merge branch 'master' of github.com:mperham/sidekiq
This commit is contained in:
commit
7eca5a22e7
5 changed files with 62 additions and 6 deletions
|
@ -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
|
||||
|
|
|
@ -95,7 +95,7 @@ module Sidekiq
|
|||
end
|
||||
|
||||
# Singleton classes are not clonable.
|
||||
SINGLETON_CLASSES = [ NilClass, TrueClass, FalseClass, Symbol, Fixnum, Float ].freeze
|
||||
SINGLETON_CLASSES = [ NilClass, TrueClass, FalseClass, Symbol, Fixnum, Float, Bignum ].freeze
|
||||
|
||||
# Clone the arguments passed to the worker so that if
|
||||
# the message fails, what is pushed back onto Redis hasn't
|
||||
|
|
|
@ -68,8 +68,8 @@ module Sidekiq
|
|||
hash
|
||||
end
|
||||
|
||||
def client_push(*args) # :nodoc:
|
||||
Sidekiq::Client.push(*args)
|
||||
def client_push(item) # :nodoc:
|
||||
Sidekiq::Client.push(stringify_keys(item))
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -29,6 +29,14 @@ class TestExtensions < MiniTest::Unit::TestCase
|
|||
assert_equal 1, Sidekiq.redis {|c| c.llen('queue:default') }
|
||||
end
|
||||
|
||||
it 'uses and stringifies specified options' do
|
||||
assert_equal [], Sidekiq::Client.registered_queues
|
||||
assert_equal 0, Sidekiq.redis {|c| c.llen('queue:notdefault') }
|
||||
MyModel.delay(queue: :notdefault).long_class_method
|
||||
assert_equal ['notdefault'], Sidekiq::Client.registered_queues
|
||||
assert_equal 1, Sidekiq.redis {|c| c.llen('queue:notdefault') }
|
||||
end
|
||||
|
||||
it 'allows delayed scheduling of AR class methods' do
|
||||
assert_equal 0, Sidekiq.redis {|c| c.zcard('schedule') }
|
||||
MyModel.delay_for(5.days).long_class_method
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Reference in a new issue