mirror of
https://github.com/mperham/sidekiq.git
synced 2022-11-09 13:52:34 -05:00
Implement optional backtrace storage [#155]
This commit is contained in:
parent
ab0a1bbf26
commit
e65efd5f0a
6 changed files with 56 additions and 0 deletions
10
Changes.md
10
Changes.md
|
@ -1,6 +1,16 @@
|
||||||
1.2.0
|
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,
|
- Add Timeout middleware to optionally kill a worker after N seconds,
|
||||||
just configure like so. (blackgold9)
|
just configure like so. (blackgold9)
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,7 @@ module Sidekiq
|
||||||
# class - the worker class to call, required
|
# class - the worker class to call, required
|
||||||
# args - an array of simple arguments to the perform method, must be JSON-serializable
|
# 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
|
# 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
|
# All options must be strings, not symbols. NB: because we are serializing to JSON, all
|
||||||
# symbols in 'args' will be converted to strings.
|
# symbols in 'args' will be converted to strings.
|
||||||
|
@ -43,6 +44,10 @@ module Sidekiq
|
||||||
item['retry'] = !!worker_class.get_sidekiq_options['retry']
|
item['retry'] = !!worker_class.get_sidekiq_options['retry']
|
||||||
queue = item['queue'] || worker_class.get_sidekiq_options['queue'] || 'default'
|
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']
|
if !item['timeout'] && worker_class.get_sidekiq_options['timeout']
|
||||||
item['timeout'] = worker_class.get_sidekiq_options['timeout']
|
item['timeout'] = worker_class.get_sidekiq_options['timeout']
|
||||||
end
|
end
|
||||||
|
|
|
@ -42,6 +42,12 @@ module Sidekiq
|
||||||
msg['retry_count'] = 0
|
msg['retry_count'] = 0
|
||||||
end
|
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
|
if count <= MAX_COUNT
|
||||||
delay = DELAY.call(count)
|
delay = DELAY.call(count)
|
||||||
logger.debug { "Failure! Retry #{count} in #{delay} seconds" }
|
logger.debug { "Failure! Retry #{count} in #{delay} seconds" }
|
||||||
|
|
|
@ -37,6 +37,8 @@ module Sidekiq
|
||||||
# :queue - use a named queue for this Worker, default 'default'
|
# :queue - use a named queue for this Worker, default 'default'
|
||||||
# :retry - enable the RetryJobs middleware for this Worker, default *true*
|
# :retry - enable the RetryJobs middleware for this Worker, default *true*
|
||||||
# :timeout - timeout the perform method after N seconds, default *nil*
|
# :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={})
|
def sidekiq_options(opts={})
|
||||||
@sidekiq_options = get_sidekiq_options.merge(stringify_keys(opts || {}))
|
@sidekiq_options = get_sidekiq_options.merge(stringify_keys(opts || {}))
|
||||||
end
|
end
|
||||||
|
|
|
@ -25,6 +25,34 @@ class TestRetry < MiniTest::Unit::TestCase
|
||||||
assert_equal msg, msg2
|
assert_equal msg, msg2
|
||||||
end
|
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
|
it 'handles a new failed message' do
|
||||||
@redis.expect :zadd, 1, ['retry', String, String]
|
@redis.expect :zadd, 1, ['retry', String, String]
|
||||||
msg = { 'class' => 'Bob', 'args' => [1,2,'foo'], 'retry' => true }
|
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 'kerblammo!', msg["error_message"]
|
||||||
assert_equal 'RuntimeError', msg["error_class"]
|
assert_equal 'RuntimeError', msg["error_class"]
|
||||||
assert_equal 0, msg["retry_count"]
|
assert_equal 0, msg["retry_count"]
|
||||||
|
refute msg["error_backtrace"]
|
||||||
assert msg["failed_at"]
|
assert msg["failed_at"]
|
||||||
@redis.verify
|
@redis.verify
|
||||||
end
|
end
|
||||||
|
|
|
@ -23,6 +23,10 @@ header
|
||||||
tr
|
tr
|
||||||
th Error Message
|
th Error Message
|
||||||
td= msg['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
|
- if msg['retry_count'] > 0
|
||||||
tr
|
tr
|
||||||
th Retry Count
|
th Retry Count
|
||||||
|
|
Loading…
Reference in a new issue