sidekiq 2.5.2 → 2.5.3
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of sidekiq might be problematic. Click here for more details.
- data/.travis.yml +2 -0
- data/Changes.md +12 -0
- data/lib/sidekiq/cli.rb +13 -10
- data/lib/sidekiq/client.rb +1 -1
- data/lib/sidekiq/extensions/action_mailer.rb +5 -1
- data/lib/sidekiq/extensions/active_record.rb +3 -0
- data/lib/sidekiq/extensions/class_methods.rb +3 -0
- data/lib/sidekiq/fetch.rb +2 -4
- data/lib/sidekiq/manager.rb +9 -11
- data/lib/sidekiq/middleware/server/logging.rb +1 -1
- data/lib/sidekiq/middleware/server/retry_jobs.rb +1 -1
- data/lib/sidekiq/processor.rb +2 -1
- data/lib/sidekiq/version.rb +1 -1
- data/lib/sidekiq/worker.rb +2 -0
- data/sidekiq.gemspec +1 -1
- data/test/test_cli.rb +22 -2
- data/test/test_client.rb +8 -1
- data/test/test_exception_handler.rb +2 -2
- data/test/test_extensions.rb +21 -0
- data/test/test_middleware.rb +3 -1
- data/test/test_processor.rb +6 -2
- data/test/test_retry.rb +18 -2
- data/test/test_stats.rb +5 -3
- data/web/assets/stylesheets/application.css +7 -42
- metadata +4 -4
data/.travis.yml
CHANGED
data/Changes.md
CHANGED
@@ -1,3 +1,15 @@
|
|
1
|
+
HEAD
|
2
|
+
-----------
|
3
|
+
|
4
|
+
- Small Web UI fixes
|
5
|
+
- Add `delay_until` so you can delay jobs until a specific timestamp:
|
6
|
+
|
7
|
+
```ruby
|
8
|
+
Auction.delay_until(@auction.ends_at).close(@auction.id)
|
9
|
+
```
|
10
|
+
|
11
|
+
This is identical to the existing Sidekiq::Worker method, `perform_at`.
|
12
|
+
|
1
13
|
2.5.2
|
2
14
|
-----------
|
3
15
|
|
data/lib/sidekiq/cli.rb
CHANGED
@@ -12,7 +12,7 @@ end
|
|
12
12
|
trap 'USR1' do
|
13
13
|
Sidekiq.logger.info "Received USR1, no longer accepting new work"
|
14
14
|
mgr = Sidekiq::CLI.instance.manager
|
15
|
-
mgr.stop
|
15
|
+
mgr.async.stop if mgr
|
16
16
|
end
|
17
17
|
|
18
18
|
trap 'TTIN' do
|
@@ -79,13 +79,13 @@ module Sidekiq
|
|
79
79
|
poller = Sidekiq::Scheduled::Poller.new
|
80
80
|
begin
|
81
81
|
logger.info 'Starting processing, hit Ctrl-C to stop'
|
82
|
-
@manager.start
|
83
|
-
poller.poll
|
82
|
+
@manager.async.start
|
83
|
+
poller.async.poll(true)
|
84
84
|
sleep
|
85
85
|
rescue Interrupt
|
86
86
|
logger.info 'Shutting down'
|
87
|
-
poller.terminate
|
88
|
-
@manager.stop
|
87
|
+
poller.async.terminate if poller.alive?
|
88
|
+
@manager.async.stop(:shutdown => true, :timeout => options[:timeout])
|
89
89
|
@manager.wait(:shutdown)
|
90
90
|
# Explicitly exit so busy Processor threads can't block
|
91
91
|
# process shutdown.
|
@@ -152,8 +152,7 @@ module Sidekiq
|
|
152
152
|
@parser = OptionParser.new do |o|
|
153
153
|
o.on "-q", "--queue QUEUE[,WEIGHT]...", "Queues to process with optional weights" do |arg|
|
154
154
|
queues_and_weights = arg.scan(/([\w\.-]+),?(\d*)/)
|
155
|
-
|
156
|
-
opts[:strict] = queues_and_weights.collect(&:last).none? {|weight| weight != ''}
|
155
|
+
parse_queues opts, queues_and_weights
|
157
156
|
end
|
158
157
|
|
159
158
|
o.on "-v", "--verbose", "Print more verbose output" do
|
@@ -215,13 +214,17 @@ module Sidekiq
|
|
215
214
|
opts = {}
|
216
215
|
if cli[:config_file] && File.exist?(cli[:config_file])
|
217
216
|
opts = YAML.load(ERB.new(IO.read(cli[:config_file])).result)
|
218
|
-
|
219
|
-
queues.each { |name, weight| parse_queues(opts, name, weight) }
|
217
|
+
parse_queues opts, opts.delete(:queues) || []
|
220
218
|
end
|
221
219
|
opts
|
222
220
|
end
|
223
221
|
|
224
|
-
def parse_queues(opts,
|
222
|
+
def parse_queues(opts, queues_and_weights)
|
223
|
+
queues_and_weights.each {|queue_and_weight| parse_queue(opts, *queue_and_weight)}
|
224
|
+
opts[:strict] = queues_and_weights.all? {|_, weight| weight.to_s.empty? }
|
225
|
+
end
|
226
|
+
|
227
|
+
def parse_queue(opts, q, weight=nil)
|
225
228
|
[weight.to_i, 1].max.times do
|
226
229
|
(opts[:queues] ||= []) << q
|
227
230
|
end
|
data/lib/sidekiq/client.rb
CHANGED
@@ -126,7 +126,7 @@ module Sidekiq
|
|
126
126
|
|
127
127
|
normalized_item = item['class'].get_sidekiq_options.merge(item.dup)
|
128
128
|
normalized_item['class'] = normalized_item['class'].to_s
|
129
|
-
normalized_item['retry'] = !!normalized_item['retry']
|
129
|
+
normalized_item['retry'] = !!normalized_item['retry'] unless normalized_item['retry'].is_a?(Fixnum)
|
130
130
|
normalized_item['jid'] = SecureRandom.hex(12)
|
131
131
|
|
132
132
|
normalized_item
|
@@ -8,6 +8,7 @@ module Sidekiq
|
|
8
8
|
#
|
9
9
|
# UserMailer.delay.send_welcome_email(new_user)
|
10
10
|
# UserMailer.delay_for(5.days).send_welcome_email(new_user)
|
11
|
+
# UserMailer.delay_until(5.days.from_now).send_welcome_email(new_user)
|
11
12
|
class DelayedMailer
|
12
13
|
include Sidekiq::Worker
|
13
14
|
# I think it's reasonable to assume that emails should take less
|
@@ -19,7 +20,7 @@ module Sidekiq
|
|
19
20
|
msg = target.send(method_name, *args)
|
20
21
|
# The email method can return nil, which causes ActionMailer to return
|
21
22
|
# an undeliverable empty message.
|
22
|
-
msg.deliver if msg && msg.to && msg.from
|
23
|
+
msg.deliver if msg && (msg.to || msg.cc || msg.bcc) && msg.from
|
23
24
|
end
|
24
25
|
end
|
25
26
|
|
@@ -30,6 +31,9 @@ module Sidekiq
|
|
30
31
|
def delay_for(interval, options={})
|
31
32
|
Proxy.new(DelayedMailer, self, options.merge('at' => Time.now.to_f + interval.to_f))
|
32
33
|
end
|
34
|
+
def delay_until(timestamp, options={})
|
35
|
+
Proxy.new(DelayedMailer, self, options.merge('at' => timestamp.to_f))
|
36
|
+
end
|
33
37
|
end
|
34
38
|
|
35
39
|
end
|
@@ -27,6 +27,9 @@ module Sidekiq
|
|
27
27
|
def delay_for(interval, options={})
|
28
28
|
Proxy.new(DelayedModel, self, options.merge('at' => Time.now.to_f + interval.to_f))
|
29
29
|
end
|
30
|
+
def delay_until(timestamp, options={})
|
31
|
+
Proxy.new(DelayedModel, self, options.merge('at' => timestamp.to_f))
|
32
|
+
end
|
30
33
|
end
|
31
34
|
|
32
35
|
end
|
@@ -25,6 +25,9 @@ module Sidekiq
|
|
25
25
|
def delay_for(interval, options={})
|
26
26
|
Proxy.new(DelayedClass, self, options.merge('at' => Time.now.to_f + interval.to_f))
|
27
27
|
end
|
28
|
+
def delay_until(timestamp, options={})
|
29
|
+
Proxy.new(DelayedClass, self, options.merge('at' => timestamp.to_f))
|
30
|
+
end
|
28
31
|
end
|
29
32
|
|
30
33
|
end
|
data/lib/sidekiq/fetch.rb
CHANGED
@@ -32,12 +32,10 @@ module Sidekiq
|
|
32
32
|
return if Sidekiq::Fetcher.done?
|
33
33
|
|
34
34
|
begin
|
35
|
-
queue =
|
36
|
-
msg = nil
|
37
|
-
Sidekiq.redis { |conn| queue, msg = conn.blpop(*queues_cmd) }
|
35
|
+
queue, msg = Sidekiq.redis { |conn| conn.blpop(*queues_cmd) }
|
38
36
|
|
39
37
|
if msg
|
40
|
-
@mgr.assign
|
38
|
+
@mgr.async.assign(msg, queue.gsub(/.*queue:/, ''))
|
41
39
|
else
|
42
40
|
after(0) { fetch }
|
43
41
|
end
|
data/lib/sidekiq/manager.rb
CHANGED
@@ -37,20 +37,12 @@ module Sidekiq
|
|
37
37
|
|
38
38
|
@done = true
|
39
39
|
Sidekiq::Fetcher.done!
|
40
|
-
@fetcher.terminate
|
40
|
+
@fetcher.async.terminate if @fetcher.alive?
|
41
41
|
|
42
42
|
logger.info { "Shutting down #{@ready.size} quiet workers" }
|
43
43
|
@ready.each { |x| x.terminate if x.alive? }
|
44
44
|
@ready.clear
|
45
45
|
|
46
|
-
logger.debug { "Clearing workers in redis" }
|
47
|
-
Sidekiq.redis do |conn|
|
48
|
-
workers = conn.smembers('workers')
|
49
|
-
workers.each do |name|
|
50
|
-
conn.srem('workers', name) if name =~ /:#{process_id}-/
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
46
|
return after(0) { signal(:shutdown) } if @busy.empty?
|
55
47
|
logger.info { "Pausing up to #{timeout} seconds to allow workers to finish..." }
|
56
48
|
hard_shutdown_in timeout if shutdown
|
@@ -108,7 +100,7 @@ module Sidekiq
|
|
108
100
|
processor = @ready.pop
|
109
101
|
@in_progress[processor.object_id] = [msg, queue]
|
110
102
|
@busy << processor
|
111
|
-
processor.process
|
103
|
+
processor.async.process(msg, queue)
|
112
104
|
end
|
113
105
|
end
|
114
106
|
end
|
@@ -123,6 +115,12 @@ module Sidekiq
|
|
123
115
|
logger.info("Still waiting for #{@busy.size} busy workers")
|
124
116
|
|
125
117
|
Sidekiq.redis do |conn|
|
118
|
+
logger.debug { "Clearing workers in redis" }
|
119
|
+
workers = conn.smembers('workers')
|
120
|
+
workers.each do |name|
|
121
|
+
conn.srem('workers', name) if name =~ /:#{process_id}-/
|
122
|
+
end
|
123
|
+
|
126
124
|
@busy.each do |processor|
|
127
125
|
# processor is an actor proxy and we can't call any methods
|
128
126
|
# that would go to the actor (since it's busy). Instead
|
@@ -146,7 +144,7 @@ module Sidekiq
|
|
146
144
|
raise "BUG: No processors, cannot continue!" if @ready.empty? && @busy.empty?
|
147
145
|
raise "No ready processor!?" if @ready.empty?
|
148
146
|
|
149
|
-
@fetcher.fetch
|
147
|
+
@fetcher.async.fetch
|
150
148
|
end
|
151
149
|
|
152
150
|
def stopped?
|
@@ -4,7 +4,7 @@ module Sidekiq
|
|
4
4
|
class Logging
|
5
5
|
|
6
6
|
def call(worker, item, queue)
|
7
|
-
Sidekiq::Logging.with_context("#{worker.class.to_s}
|
7
|
+
Sidekiq::Logging.with_context("#{worker.class.to_s} JID-#{item['jid']}") do
|
8
8
|
begin
|
9
9
|
start = Time.now
|
10
10
|
logger.info { "start" }
|
@@ -68,7 +68,7 @@ module Sidekiq
|
|
68
68
|
msg['error_backtrace'] = e.backtrace[0..msg['backtrace'].to_i]
|
69
69
|
end
|
70
70
|
|
71
|
-
if count
|
71
|
+
if count < max_retry_attempts
|
72
72
|
delay = DELAY.call(count)
|
73
73
|
logger.debug { "Failure! Retry #{count} in #{delay} seconds" }
|
74
74
|
retry_at = Time.now.to_f + delay
|
data/lib/sidekiq/processor.rb
CHANGED
@@ -36,6 +36,7 @@ module Sidekiq
|
|
36
36
|
msg = Sidekiq.load_json(msgstr)
|
37
37
|
klass = msg['class'].constantize
|
38
38
|
worker = klass.new
|
39
|
+
worker.jid = msg['jid']
|
39
40
|
|
40
41
|
stats(worker, msg, queue) do
|
41
42
|
Sidekiq.server_middleware.invoke(worker, msg, queue) do
|
@@ -47,7 +48,7 @@ module Sidekiq
|
|
47
48
|
raise
|
48
49
|
end
|
49
50
|
end
|
50
|
-
@boss.processor_done
|
51
|
+
@boss.async.processor_done(current_actor)
|
51
52
|
end
|
52
53
|
|
53
54
|
# See http://github.com/tarcieri/celluloid/issues/22
|
data/lib/sidekiq/version.rb
CHANGED
data/lib/sidekiq/worker.rb
CHANGED
data/sidekiq.gemspec
CHANGED
@@ -19,7 +19,7 @@ Gem::Specification.new do |gem|
|
|
19
19
|
gem.add_dependency 'connection_pool', '~> 0.9.2'
|
20
20
|
gem.add_dependency 'celluloid', '~> 0.12.0'
|
21
21
|
gem.add_dependency 'multi_json', '~> 1'
|
22
|
-
gem.add_development_dependency 'minitest', '~>
|
22
|
+
gem.add_development_dependency 'minitest', '~> 4'
|
23
23
|
gem.add_development_dependency 'sinatra'
|
24
24
|
gem.add_development_dependency 'slim'
|
25
25
|
gem.add_development_dependency 'rake'
|
data/test/test_cli.rb
CHANGED
@@ -190,10 +190,30 @@ class TestCli < MiniTest::Unit::TestCase
|
|
190
190
|
end
|
191
191
|
|
192
192
|
describe 'Sidekiq::CLI#parse_queues' do
|
193
|
+
describe 'when weight is present' do
|
194
|
+
it 'concatenates queues by factor of weight and sets strict to false' do
|
195
|
+
opts = {}
|
196
|
+
@cli.send :parse_queues, opts, [['often', 7]]
|
197
|
+
assert_equal %w[often] * 7, opts[:queues]
|
198
|
+
assert !opts[:strict]
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
describe 'when weight is not present' do
|
203
|
+
it 'returns queues and sets strict' do
|
204
|
+
opts = {}
|
205
|
+
@cli.send :parse_queues, opts, [['once']]
|
206
|
+
assert_equal %w[once], opts[:queues]
|
207
|
+
assert opts[:strict]
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
describe 'Sidekiq::CLI#parse_queue' do
|
193
213
|
describe 'when weight is present' do
|
194
214
|
it 'concatenates queue to opts[:queues] weight number of times' do
|
195
215
|
opts = {}
|
196
|
-
@cli.send :
|
216
|
+
@cli.send :parse_queue, opts, 'often', 7
|
197
217
|
assert_equal %w[often] * 7, opts[:queues]
|
198
218
|
end
|
199
219
|
end
|
@@ -201,7 +221,7 @@ class TestCli < MiniTest::Unit::TestCase
|
|
201
221
|
describe 'when weight is not present' do
|
202
222
|
it 'concatenates queue to opts[:queues] once' do
|
203
223
|
opts = {}
|
204
|
-
@cli.send :
|
224
|
+
@cli.send :parse_queue, opts, 'once', nil
|
205
225
|
assert_equal %w[once], opts[:queues]
|
206
226
|
end
|
207
227
|
end
|
data/test/test_client.rb
CHANGED
@@ -116,6 +116,9 @@ class TestClient < MiniTest::Unit::TestCase
|
|
116
116
|
class BWorker < BaseWorker
|
117
117
|
sidekiq_options 'retry' => 'b'
|
118
118
|
end
|
119
|
+
class CWorker < BaseWorker
|
120
|
+
sidekiq_options 'retry' => 2
|
121
|
+
end
|
119
122
|
|
120
123
|
describe 'client middleware' do
|
121
124
|
|
@@ -138,7 +141,7 @@ class TestClient < MiniTest::Unit::TestCase
|
|
138
141
|
end
|
139
142
|
|
140
143
|
describe 'inheritance' do
|
141
|
-
it '
|
144
|
+
it 'inherits sidekiq options' do
|
142
145
|
assert_equal 'base', AWorker.get_sidekiq_options['retry']
|
143
146
|
assert_equal 'b', BWorker.get_sidekiq_options['retry']
|
144
147
|
end
|
@@ -148,5 +151,9 @@ class TestClient < MiniTest::Unit::TestCase
|
|
148
151
|
it 'defaults retry to true' do
|
149
152
|
assert_equal true, Sidekiq::Client.normalize_item('class' => QueuedWorker, 'args' => [])['retry']
|
150
153
|
end
|
154
|
+
|
155
|
+
it "does not normalize numeric retry's" do
|
156
|
+
assert_equal 2, Sidekiq::Client.normalize_item('class' => CWorker, 'args' => [])['retry']
|
157
|
+
end
|
151
158
|
end
|
152
159
|
end
|
@@ -8,7 +8,7 @@ ExceptionHandlerTestException = Class.new(StandardError)
|
|
8
8
|
TEST_EXCEPTION = ExceptionHandlerTestException.new("Something didn't work!")
|
9
9
|
|
10
10
|
class Component
|
11
|
-
include Sidekiq::
|
11
|
+
include Sidekiq::ExceptionHandler
|
12
12
|
|
13
13
|
def invoke_exception(args)
|
14
14
|
raise TEST_EXCEPTION
|
@@ -115,7 +115,7 @@ class TestExceptionHandler < MiniTest::Unit::TestCase
|
|
115
115
|
|
116
116
|
it "notifies Exceptional" do
|
117
117
|
::Exceptional::Config.expect(:should_send_to_api?,true)
|
118
|
-
exception_data =
|
118
|
+
exception_data = Object.new
|
119
119
|
::Exceptional::Remote.expect(:error,nil,[exception_data])
|
120
120
|
::Exceptional::ExceptionData.expect(:new,exception_data,[TEST_EXCEPTION])
|
121
121
|
Component.new.invoke_exception(:c => 3)
|
data/test/test_extensions.rb
CHANGED
@@ -43,6 +43,12 @@ class TestExtensions < MiniTest::Unit::TestCase
|
|
43
43
|
assert_equal 1, Sidekiq.redis {|c| c.zcard('schedule') }
|
44
44
|
end
|
45
45
|
|
46
|
+
it 'allows until delayed scheduling of AR class methods' do
|
47
|
+
assert_equal 0, Sidekiq.redis {|c| c.zcard('schedule') }
|
48
|
+
MyModel.delay_until(1.day.from_now).long_class_method
|
49
|
+
assert_equal 1, Sidekiq.redis {|c| c.zcard('schedule') }
|
50
|
+
end
|
51
|
+
|
46
52
|
class UserMailer < ActionMailer::Base
|
47
53
|
def greetings(a, b)
|
48
54
|
raise "Should not be called!"
|
@@ -63,13 +69,21 @@ class TestExtensions < MiniTest::Unit::TestCase
|
|
63
69
|
assert_equal 1, Sidekiq.redis {|c| c.zcard('schedule') }
|
64
70
|
end
|
65
71
|
|
72
|
+
it 'allows until delay scheduling of AM mails' do
|
73
|
+
assert_equal 0, Sidekiq.redis {|c| c.zcard('schedule') }
|
74
|
+
UserMailer.delay_until(5.days.from_now).greetings(1, 2)
|
75
|
+
assert_equal 1, Sidekiq.redis {|c| c.zcard('schedule') }
|
76
|
+
end
|
77
|
+
|
66
78
|
class SomeClass
|
67
79
|
def self.doit(arg)
|
68
80
|
end
|
69
81
|
end
|
70
82
|
|
71
83
|
it 'allows delay of any ole class method' do
|
84
|
+
assert_equal 0, queue_size
|
72
85
|
SomeClass.delay.doit(Date.today)
|
86
|
+
assert_equal 1, queue_size
|
73
87
|
end
|
74
88
|
|
75
89
|
module SomeModule
|
@@ -78,7 +92,14 @@ class TestExtensions < MiniTest::Unit::TestCase
|
|
78
92
|
end
|
79
93
|
|
80
94
|
it 'allows delay of any module class method' do
|
95
|
+
assert_equal 0, queue_size
|
81
96
|
SomeModule.delay.doit(Date.today)
|
97
|
+
assert_equal 1, queue_size
|
98
|
+
end
|
99
|
+
|
100
|
+
def queue_size(name='default')
|
101
|
+
Sidekiq::Queue.new(name).size
|
82
102
|
end
|
83
103
|
end
|
104
|
+
|
84
105
|
end
|
data/test/test_middleware.rb
CHANGED
@@ -52,7 +52,9 @@ class TestMiddleware < MiniTest::Unit::TestCase
|
|
52
52
|
|
53
53
|
boss = MiniTest::Mock.new
|
54
54
|
processor = Sidekiq::Processor.new(boss)
|
55
|
-
|
55
|
+
actor = MiniTest::Mock.new
|
56
|
+
actor.expect(:processor_done, nil, [processor])
|
57
|
+
boss.expect(:async, actor, [])
|
56
58
|
processor.process(msg, 'default')
|
57
59
|
assert_equal %w(0 before work_performed 0 after), $recorder.flatten
|
58
60
|
end
|
data/test/test_processor.rb
CHANGED
@@ -25,7 +25,9 @@ class TestProcessor < MiniTest::Unit::TestCase
|
|
25
25
|
|
26
26
|
it 'processes as expected' do
|
27
27
|
msg = Sidekiq.dump_json({ 'class' => MockWorker.to_s, 'args' => ['myarg'] })
|
28
|
-
|
28
|
+
actor = MiniTest::Mock.new
|
29
|
+
actor.expect(:processor_done, nil, [@processor])
|
30
|
+
@boss.expect(:async, actor, [])
|
29
31
|
@processor.process(msg, 'default')
|
30
32
|
@boss.verify
|
31
33
|
assert_equal 1, $invokes
|
@@ -59,7 +61,9 @@ class TestProcessor < MiniTest::Unit::TestCase
|
|
59
61
|
msg = { 'class' => MockWorker.to_s, 'args' => [['myarg']] }
|
60
62
|
msgstr = Sidekiq.dump_json(msg)
|
61
63
|
processor = ::Sidekiq::Processor.new(@boss)
|
62
|
-
|
64
|
+
actor = MiniTest::Mock.new
|
65
|
+
actor.expect(:processor_done, nil, [processor])
|
66
|
+
@boss.expect(:async, actor, [])
|
63
67
|
processor.process(msgstr, 'default')
|
64
68
|
assert_equal [['myarg']], msg['args']
|
65
69
|
end
|
data/test/test_retry.rb
CHANGED
@@ -24,6 +24,21 @@ class TestRetry < MiniTest::Unit::TestCase
|
|
24
24
|
assert_equal msg, msg2
|
25
25
|
end
|
26
26
|
|
27
|
+
it 'allows a numeric retry' do
|
28
|
+
@redis.expect :zadd, 1, ['retry', String, String]
|
29
|
+
msg = { 'class' => 'Bob', 'args' => [1,2,'foo'], 'retry' => 2 }
|
30
|
+
msg2 = msg.dup
|
31
|
+
handler = Sidekiq::Middleware::Server::RetryJobs.new
|
32
|
+
assert_raises RuntimeError do
|
33
|
+
handler.call('', msg2, 'default') do
|
34
|
+
raise "kerblammo!"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
msg2.delete('failed_at')
|
38
|
+
assert_equal({"class"=>"Bob", "args"=>[1, 2, "foo"], "retry"=>2, "queue"=>"default", "error_message"=>"kerblammo!", "error_class"=>"RuntimeError", "retry_count"=>0}, msg2)
|
39
|
+
@redis.verify
|
40
|
+
end
|
41
|
+
|
27
42
|
it 'saves backtraces' do
|
28
43
|
@redis.expect :zadd, 1, ['retry', String, String]
|
29
44
|
msg = { 'class' => 'Bob', 'args' => [1,2,'foo'], 'retry' => true, 'backtrace' => true }
|
@@ -36,6 +51,7 @@ class TestRetry < MiniTest::Unit::TestCase
|
|
36
51
|
end
|
37
52
|
assert msg["error_backtrace"]
|
38
53
|
assert_equal c[0], msg["error_backtrace"][0]
|
54
|
+
@redis.verify
|
39
55
|
end
|
40
56
|
|
41
57
|
it 'saves partial backtraces' do
|
@@ -91,7 +107,7 @@ class TestRetry < MiniTest::Unit::TestCase
|
|
91
107
|
it 'handles a recurring failed message before reaching user-specifed max' do
|
92
108
|
@redis.expect :zadd, 1, ['retry', String, String]
|
93
109
|
now = Time.now.utc
|
94
|
-
msg = {"class"=>"Bob", "args"=>[1, 2, "foo"], 'retry' =>
|
110
|
+
msg = {"class"=>"Bob", "args"=>[1, 2, "foo"], 'retry' => 10, "queue"=>"default", "error_message"=>"kerblammo!", "error_class"=>"RuntimeError", "failed_at"=>now, "retry_count"=>8}
|
95
111
|
handler = Sidekiq::Middleware::Server::RetryJobs.new
|
96
112
|
assert_raises RuntimeError do
|
97
113
|
handler.call('', msg, 'default') do
|
@@ -101,7 +117,7 @@ class TestRetry < MiniTest::Unit::TestCase
|
|
101
117
|
assert_equal 'default', msg["queue"]
|
102
118
|
assert_equal 'kerblammo!', msg["error_message"]
|
103
119
|
assert_equal 'RuntimeError', msg["error_class"]
|
104
|
-
assert_equal
|
120
|
+
assert_equal 9, msg["retry_count"]
|
105
121
|
assert msg["failed_at"]
|
106
122
|
@redis.verify
|
107
123
|
end
|
data/test/test_stats.rb
CHANGED
@@ -21,6 +21,7 @@ class TestStats < MiniTest::Unit::TestCase
|
|
21
21
|
it 'updates global stats in the success case' do
|
22
22
|
msg = Sidekiq.dump_json({ 'class' => DumbWorker.to_s, 'args' => [""] })
|
23
23
|
boss = MiniTest::Mock.new
|
24
|
+
actor = MiniTest::Mock.new
|
24
25
|
|
25
26
|
@redis.with do |conn|
|
26
27
|
|
@@ -28,9 +29,10 @@ class TestStats < MiniTest::Unit::TestCase
|
|
28
29
|
assert_equal 0, set.size
|
29
30
|
|
30
31
|
processor = Sidekiq::Processor.new(boss)
|
31
|
-
|
32
|
-
|
33
|
-
|
32
|
+
3.times do
|
33
|
+
actor.expect(:processor_done, nil, [processor])
|
34
|
+
boss.expect(:async, actor, [])
|
35
|
+
end
|
34
36
|
|
35
37
|
assert_equal 0, Sidekiq.info[:failed]
|
36
38
|
assert_equal 0, Sidekiq.info[:processed]
|
@@ -1,9 +1,5 @@
|
|
1
|
-
@import url(
|
2
|
-
@import url(
|
3
|
-
|
4
|
-
//
|
5
|
-
// Base
|
6
|
-
//
|
1
|
+
@import url(//fonts.googleapis.com/css?family=Gudea:400,700);
|
2
|
+
@import url(//fonts.googleapis.com/css?family=Armata);
|
7
3
|
|
8
4
|
* {
|
9
5
|
box-sizing: border-box;
|
@@ -69,7 +65,6 @@ h1, h2, h3, h4, h5, h6, strong {
|
|
69
65
|
.title, .admin .brand {
|
70
66
|
background: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #b1003e), color-stop(100%, #310011));
|
71
67
|
background: -webkit-linear-gradient(#b1003e, #310011);
|
72
|
-
background: -moz-linear-gradient(#b1003e, #310011);
|
73
68
|
background: -o-linear-gradient(#b1003e, #310011);
|
74
69
|
background: linear-gradient(#b1003e, #310011);
|
75
70
|
-webkit-background-clip: text;
|
@@ -109,10 +104,6 @@ code {
|
|
109
104
|
border: none;
|
110
105
|
}
|
111
106
|
|
112
|
-
//
|
113
|
-
// Layout
|
114
|
-
//
|
115
|
-
|
116
107
|
section {
|
117
108
|
padding-top: 10px;
|
118
109
|
}
|
@@ -295,10 +286,6 @@ td form {
|
|
295
286
|
}
|
296
287
|
}
|
297
288
|
|
298
|
-
//
|
299
|
-
// Prettify
|
300
|
-
//
|
301
|
-
|
302
289
|
.com {
|
303
290
|
color: #93a1a1;
|
304
291
|
}
|
@@ -354,10 +341,6 @@ ol.linenums li {
|
|
354
341
|
text-shadow: 0 1px 0 #fff;
|
355
342
|
}
|
356
343
|
|
357
|
-
//
|
358
|
-
// Navbar
|
359
|
-
//
|
360
|
-
|
361
344
|
.navbar-container {
|
362
345
|
height: 40px;
|
363
346
|
}
|
@@ -463,14 +446,12 @@ img.smallogo {
|
|
463
446
|
margin-right: 20px;
|
464
447
|
}
|
465
448
|
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
background: url('/assets/status-sd8051fd480.png') no-repeat;
|
449
|
+
.status-sprite {
|
450
|
+
background-image: url(/images/status-sd8051fd480.png);
|
451
|
+
height: 30px;
|
452
|
+
width: 30px;
|
453
|
+
display: inline-block;
|
472
454
|
}
|
473
|
-
|
474
455
|
.status-active {
|
475
456
|
background-position: 0 0;
|
476
457
|
}
|
@@ -479,10 +460,6 @@ img.smallogo {
|
|
479
460
|
background-position: 0 -80px;
|
480
461
|
}
|
481
462
|
|
482
|
-
//
|
483
|
-
// Style
|
484
|
-
//
|
485
|
-
|
486
463
|
.btn {
|
487
464
|
font-weight: 700;
|
488
465
|
border: none;
|
@@ -530,15 +507,3 @@ img.smallogo {
|
|
530
507
|
padding: 10px 0;
|
531
508
|
}
|
532
509
|
|
533
|
-
.status-idle {
|
534
|
-
height: 30px;
|
535
|
-
width: 30px;
|
536
|
-
display: inline-block;
|
537
|
-
}
|
538
|
-
|
539
|
-
.status-active {
|
540
|
-
height: 30px;
|
541
|
-
width: 30px;
|
542
|
-
display: inline-block;
|
543
|
-
}
|
544
|
-
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sidekiq
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.5.
|
4
|
+
version: 2.5.3
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-11-
|
12
|
+
date: 2012-11-15 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: redis
|
@@ -98,7 +98,7 @@ dependencies:
|
|
98
98
|
requirements:
|
99
99
|
- - ~>
|
100
100
|
- !ruby/object:Gem::Version
|
101
|
-
version: '
|
101
|
+
version: '4'
|
102
102
|
type: :development
|
103
103
|
prerelease: false
|
104
104
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -106,7 +106,7 @@ dependencies:
|
|
106
106
|
requirements:
|
107
107
|
- - ~>
|
108
108
|
- !ruby/object:Gem::Version
|
109
|
-
version: '
|
109
|
+
version: '4'
|
110
110
|
- !ruby/object:Gem::Dependency
|
111
111
|
name: sinatra
|
112
112
|
requirement: !ruby/object:Gem::Requirement
|