Implement optional backtrace storage [#155]

This commit is contained in:
Mike Perham 2012-04-27 20:25:46 -07:00
parent ab0a1bbf26
commit e65efd5f0a
6 changed files with 56 additions and 0 deletions

View File

@ -1,6 +1,16 @@
1.2.0
-----------
- Error backtraces can optionally be stored as part of the retry,
for display in the web UI if you aren't using an error service. [#155]
```ruby
class Worker
include Sidekiq::Worker
sidekiq_options :backtrace => true || 10
end
```
- Add Timeout middleware to optionally kill a worker after N seconds,
just configure like so. (blackgold9)

View File

@ -26,6 +26,7 @@ module Sidekiq
# class - the worker class to call, required
# args - an array of simple arguments to the perform method, must be JSON-serializable
# retry - whether to retry this job if it fails, true or false, default true
# backtrace - whether to save any error backtrace, default false
#
# All options must be strings, not symbols. NB: because we are serializing to JSON, all
# symbols in 'args' will be converted to strings.
@ -43,6 +44,10 @@ module Sidekiq
item['retry'] = !!worker_class.get_sidekiq_options['retry']
queue = item['queue'] || worker_class.get_sidekiq_options['queue'] || 'default'
if !item['backtrace'] && worker_class.get_sidekiq_options['backtrace']
item['backtrace'] = worker_class.get_sidekiq_options['backtrace']
end
if !item['timeout'] && worker_class.get_sidekiq_options['timeout']
item['timeout'] = worker_class.get_sidekiq_options['timeout']
end

View File

@ -42,6 +42,12 @@ module Sidekiq
msg['retry_count'] = 0
end
if msg['backtrace'] == true
msg['error_backtrace'] = e.backtrace
elsif msg['backtrace'].to_i != 0
msg['error_backtrace'] = e.backtrace[0..msg['backtrace'].to_i]
end
if count <= MAX_COUNT
delay = DELAY.call(count)
logger.debug { "Failure! Retry #{count} in #{delay} seconds" }

View File

@ -37,6 +37,8 @@ module Sidekiq
# :queue - use a named queue for this Worker, default 'default'
# :retry - enable the RetryJobs middleware for this Worker, default *true*
# :timeout - timeout the perform method after N seconds, default *nil*
# :backtrace - whether to save any error backtrace in the retry payload to display in web UI,
# can be true, false or an integer number of lines to save, default *false*
def sidekiq_options(opts={})
@sidekiq_options = get_sidekiq_options.merge(stringify_keys(opts || {}))
end

View File

@ -25,6 +25,34 @@ class TestRetry < MiniTest::Unit::TestCase
assert_equal msg, msg2
end
it 'saves backtraces' do
@redis.expect :zadd, 1, ['retry', String, String]
msg = { 'class' => 'Bob', 'args' => [1,2,'foo'], 'retry' => true, 'backtrace' => true }
handler = Sidekiq::Middleware::Server::RetryJobs.new
c = nil
assert_raises RuntimeError do
handler.call('', msg, 'default') do
c = caller(0); raise "kerblammo!"
end
end
assert msg["error_backtrace"]
assert_equal c, msg["error_backtrace"]
end
it 'saves partial backtraces' do
@redis.expect :zadd, 1, ['retry', String, String]
msg = { 'class' => 'Bob', 'args' => [1,2,'foo'], 'retry' => true, 'backtrace' => 3 }
handler = Sidekiq::Middleware::Server::RetryJobs.new
c = nil
assert_raises RuntimeError do
handler.call('', msg, 'default') do
c = caller(0)[0..3]; raise "kerblammo!"
end
end
assert msg["error_backtrace"]
assert_equal c, msg["error_backtrace"]
end
it 'handles a new failed message' do
@redis.expect :zadd, 1, ['retry', String, String]
msg = { 'class' => 'Bob', 'args' => [1,2,'foo'], 'retry' => true }
@ -38,6 +66,7 @@ class TestRetry < MiniTest::Unit::TestCase
assert_equal 'kerblammo!', msg["error_message"]
assert_equal 'RuntimeError', msg["error_class"]
assert_equal 0, msg["retry_count"]
refute msg["error_backtrace"]
assert msg["failed_at"]
@redis.verify
end

View File

@ -23,6 +23,10 @@ header
tr
th Error Message
td= msg['error_message']
- if !msg['error_backtrace'].nil?
tr
th Error Backtrace
td== msg['error_backtrace'].join("<br/>")
- if msg['retry_count'] > 0
tr
th Retry Count