sidekiq 3.5.4 → 4.0.0.pre1

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.

@@ -19,6 +19,12 @@ module Sidekiq
19
19
  raise ex
20
20
  end
21
21
 
22
+ def safe_thread(name, &block)
23
+ Thread.new do
24
+ watchdog(name, &block)
25
+ end
26
+ end
27
+
22
28
  def logger
23
29
  Sidekiq.logger
24
30
  end
@@ -49,6 +55,7 @@ module Sidekiq
49
55
  handle_exception(ex, { event: event })
50
56
  end
51
57
  end
58
+ arr.clear
52
59
  end
53
60
 
54
61
  def want_a_hertz_donut?
@@ -1,3 +1,3 @@
1
1
  module Sidekiq
2
- VERSION = "3.5.4"
2
+ VERSION = "4.0.0.pre1"
3
3
  end
@@ -18,8 +18,8 @@ Gem::Specification.new do |gem|
18
18
  gem.add_dependency 'redis', '~> 3.2', '>= 3.2.1'
19
19
  gem.add_dependency 'redis-namespace', '~> 1.5', '>= 1.5.2'
20
20
  gem.add_dependency 'connection_pool', '~> 2.2', '>= 2.2.0'
21
- gem.add_dependency 'celluloid', '~> 0.17.2'
22
21
  gem.add_dependency 'json', '~> 1.0'
22
+ gem.add_dependency 'concurrent-ruby', '1.0.0.pre4'
23
23
  gem.add_development_dependency 'sinatra', '~> 1.4', '>= 1.4.6'
24
24
  gem.add_development_dependency 'minitest', '~> 5.7', '>= 5.7.0'
25
25
  gem.add_development_dependency 'rake', '~> 10.0'
@@ -1,5 +1,7 @@
1
- $CELLULOID_DEBUG = false
2
1
  $TESTING = true
2
+ # disable minitest/parallel threads
3
+ ENV["N"] = "0"
4
+
3
5
  if ENV["COVERAGE"]
4
6
  require 'simplecov'
5
7
  SimpleCov.start do
@@ -9,17 +11,30 @@ if ENV["COVERAGE"]
9
11
  end
10
12
  ENV['RACK_ENV'] = ENV['RAILS_ENV'] = 'test'
11
13
 
14
+ trap 'USR1' do
15
+ threads = Thread.list
16
+
17
+ puts
18
+ puts "=" * 80
19
+ puts "Received USR1 signal; printing all #{threads.count} thread backtraces."
20
+
21
+ threads.each do |thr|
22
+ description = thr == Thread.main ? "Main thread" : thr.inspect
23
+ puts
24
+ puts "#{description} backtrace: "
25
+ puts thr.backtrace.join("\n")
26
+ end
27
+
28
+ puts "=" * 80
29
+ end
30
+
12
31
  begin
13
32
  require 'pry-byebug'
14
33
  rescue LoadError
15
34
  end
16
35
 
17
36
  require 'minitest/autorun'
18
- require 'minitest/pride'
19
37
 
20
- require 'celluloid/current'
21
- require 'celluloid/test'
22
- Celluloid.boot
23
38
  require 'sidekiq'
24
39
  require 'sidekiq/util'
25
40
  Sidekiq.logger.level = Logger::ERROR
@@ -47,3 +62,13 @@ def capture_logging(lvl=Logger::INFO)
47
62
  Sidekiq.logger = old
48
63
  end
49
64
  end
65
+
66
+ def with_logging(lvl=Logger::DEBUG)
67
+ old = Sidekiq.logger.level
68
+ begin
69
+ Sidekiq.logger.level = lvl
70
+ yield
71
+ ensure
72
+ Sidekiq.logger.level = old
73
+ end
74
+ end
@@ -0,0 +1,137 @@
1
+ require_relative 'helper'
2
+ require 'sidekiq/cli'
3
+ require 'sidekiq/fetch'
4
+ require 'sidekiq/scheduled'
5
+ require 'sidekiq/processor'
6
+
7
+ class TestActors < Sidekiq::Test
8
+ class JoeWorker
9
+ include Sidekiq::Worker
10
+ def perform(slp)
11
+ raise "boom" if slp == "boom"
12
+ sleep(slp) if slp > 0
13
+ $count += 1
14
+ end
15
+ end
16
+
17
+ describe 'threads' do
18
+ before do
19
+ Sidekiq.redis {|c| c.flushdb}
20
+ end
21
+
22
+ describe 'scheduler' do
23
+ it 'can start and stop' do
24
+ f = Sidekiq::Scheduled::Poller.new
25
+ f.start
26
+ f.terminate
27
+ end
28
+
29
+ it 'can schedule' do
30
+ ss = Sidekiq::ScheduledSet.new
31
+ q = Sidekiq::Queue.new
32
+
33
+ JoeWorker.perform_in(0.01, 0)
34
+
35
+ assert_equal 0, q.size
36
+ assert_equal 1, ss.size
37
+
38
+ sleep 0.015
39
+ s = Sidekiq::Scheduled::Poller.new
40
+ s.enqueue
41
+ assert_equal 1, q.size
42
+ assert_equal 0, ss.size
43
+ s.terminate
44
+ end
45
+ end
46
+
47
+ describe 'processor' do
48
+ before do
49
+ $count = 0
50
+ end
51
+
52
+ it 'can start and stop' do
53
+ f = Sidekiq::Processor.new(Mgr.new)
54
+ f.terminate
55
+ end
56
+
57
+ class Mgr
58
+ attr_reader :latest_error
59
+ attr_reader :mutex
60
+ attr_reader :cond
61
+ def initialize
62
+ @mutex = ::Mutex.new
63
+ @cond = ::ConditionVariable.new
64
+ end
65
+ def processor_died(inst, err)
66
+ @latest_error = err
67
+ @mutex.synchronize do
68
+ @cond.signal
69
+ end
70
+ end
71
+ def processor_stopped(inst)
72
+ @mutex.synchronize do
73
+ @cond.signal
74
+ end
75
+ end
76
+ def options
77
+ { :concurrency => 3, :queues => ['default'] }
78
+ end
79
+ end
80
+
81
+ it 'can process' do
82
+ mgr = Mgr.new
83
+
84
+ p = Sidekiq::Processor.new(mgr)
85
+ JoeWorker.perform_async(0)
86
+
87
+ a = $count
88
+ p.process_one
89
+ b = $count
90
+ assert_equal a + 1, b
91
+ end
92
+
93
+ it 'deals with errors' do
94
+ mgr = Mgr.new
95
+
96
+ p = Sidekiq::Processor.new(mgr)
97
+ JoeWorker.perform_async("boom")
98
+ q = Sidekiq::Queue.new
99
+ assert_equal 1, q.size
100
+
101
+ a = $count
102
+ mgr.mutex.synchronize do
103
+ p.start
104
+ mgr.cond.wait(mgr.mutex)
105
+ end
106
+ b = $count
107
+ assert_equal a, b
108
+
109
+ sleep 0.001
110
+ assert_equal false, p.thread.status
111
+ p.terminate(true)
112
+ refute_nil mgr.latest_error
113
+ assert_equal RuntimeError, mgr.latest_error.class
114
+ end
115
+
116
+ it 'gracefully kills' do
117
+ mgr = Mgr.new
118
+
119
+ p = Sidekiq::Processor.new(mgr)
120
+ JoeWorker.perform_async(1)
121
+ q = Sidekiq::Queue.new
122
+ assert_equal 1, q.size
123
+
124
+ a = $count
125
+ p.start
126
+ sleep(0.02)
127
+ p.terminate
128
+ p.kill(true)
129
+
130
+ b = $count
131
+ assert_equal a, b
132
+ assert_equal false, p.thread.status
133
+ refute mgr.latest_error, mgr.latest_error.to_s
134
+ end
135
+ end
136
+ end
137
+ end
@@ -1,492 +1,493 @@
1
1
  require_relative 'helper'
2
+ require 'sidekiq/api'
2
3
 
3
4
  class TestApi < Sidekiq::Test
4
-
5
- describe "stats" do
6
-
7
- it "is initially zero" do
5
+ describe 'api' do
6
+ before do
8
7
  Sidekiq.redis {|c| c.flushdb }
9
- s = Sidekiq::Stats.new
10
- assert_equal 0, s.processed
11
- assert_equal 0, s.failed
12
- assert_equal 0, s.enqueued
13
8
  end
14
9
 
15
- describe "processed" do
16
- it "returns number of processed jobs" do
17
- Sidekiq.redis { |conn| conn.set("stat:processed", 5) }
10
+ describe "stats" do
11
+ it "is initially zero" do
18
12
  s = Sidekiq::Stats.new
19
- assert_equal 5, s.processed
13
+ assert_equal 0, s.processed
14
+ assert_equal 0, s.failed
15
+ assert_equal 0, s.enqueued
20
16
  end
21
- end
22
17
 
23
- describe "failed" do
24
- it "returns number of failed jobs" do
25
- Sidekiq.redis { |conn| conn.set("stat:failed", 5) }
26
- s = Sidekiq::Stats.new
27
- assert_equal 5, s.failed
28
- end
29
- end
30
-
31
- describe "reset" do
32
- before do
33
- Sidekiq.redis do |conn|
34
- conn.set('stat:processed', 5)
35
- conn.set('stat:failed', 10)
18
+ describe "processed" do
19
+ it "returns number of processed jobs" do
20
+ Sidekiq.redis { |conn| conn.set("stat:processed", 5) }
21
+ s = Sidekiq::Stats.new
22
+ assert_equal 5, s.processed
36
23
  end
37
24
  end
38
25
 
39
- it 'will reset all stats by default' do
40
- Sidekiq::Stats.new.reset
41
- s = Sidekiq::Stats.new
42
- assert_equal 0, s.failed
43
- assert_equal 0, s.processed
26
+ describe "failed" do
27
+ it "returns number of failed jobs" do
28
+ Sidekiq.redis { |conn| conn.set("stat:failed", 5) }
29
+ s = Sidekiq::Stats.new
30
+ assert_equal 5, s.failed
31
+ end
44
32
  end
45
33
 
46
- it 'can reset individual stats' do
47
- Sidekiq::Stats.new.reset('failed')
48
- s = Sidekiq::Stats.new
49
- assert_equal 0, s.failed
50
- assert_equal 5, s.processed
51
- end
34
+ describe "reset" do
35
+ before do
36
+ Sidekiq.redis do |conn|
37
+ conn.set('stat:processed', 5)
38
+ conn.set('stat:failed', 10)
39
+ end
40
+ end
52
41
 
53
- it 'can accept anything that responds to #to_s' do
54
- Sidekiq::Stats.new.reset(:failed)
55
- s = Sidekiq::Stats.new
56
- assert_equal 0, s.failed
57
- assert_equal 5, s.processed
58
- end
42
+ it 'will reset all stats by default' do
43
+ Sidekiq::Stats.new.reset
44
+ s = Sidekiq::Stats.new
45
+ assert_equal 0, s.failed
46
+ assert_equal 0, s.processed
47
+ end
59
48
 
60
- it 'ignores anything other than "failed" or "processed"' do
61
- Sidekiq::Stats.new.reset((1..10).to_a, ['failed'])
62
- s = Sidekiq::Stats.new
63
- assert_equal 0, s.failed
64
- assert_equal 5, s.processed
65
- end
66
- end
49
+ it 'can reset individual stats' do
50
+ Sidekiq::Stats.new.reset('failed')
51
+ s = Sidekiq::Stats.new
52
+ assert_equal 0, s.failed
53
+ assert_equal 5, s.processed
54
+ end
67
55
 
68
- describe "queues" do
69
- before do
70
- Sidekiq.redis {|c| c.flushdb }
71
- end
56
+ it 'can accept anything that responds to #to_s' do
57
+ Sidekiq::Stats.new.reset(:failed)
58
+ s = Sidekiq::Stats.new
59
+ assert_equal 0, s.failed
60
+ assert_equal 5, s.processed
61
+ end
72
62
 
73
- it "is initially empty" do
74
- s = Sidekiq::Stats::Queues.new
75
- assert_equal 0, s.lengths.size
63
+ it 'ignores anything other than "failed" or "processed"' do
64
+ Sidekiq::Stats.new.reset((1..10).to_a, ['failed'])
65
+ s = Sidekiq::Stats.new
66
+ assert_equal 0, s.failed
67
+ assert_equal 5, s.processed
68
+ end
76
69
  end
77
70
 
78
- it "returns a hash of queue and size in order" do
79
- Sidekiq.redis do |conn|
80
- conn.rpush 'queue:foo', '{}'
81
- conn.sadd 'queues', 'foo'
82
-
83
- 3.times { conn.rpush 'queue:bar', '{}' }
84
- conn.sadd 'queues', 'bar'
71
+ describe "queues" do
72
+ it "is initially empty" do
73
+ s = Sidekiq::Stats::Queues.new
74
+ assert_equal 0, s.lengths.size
85
75
  end
86
76
 
87
- s = Sidekiq::Stats::Queues.new
88
- assert_equal ({ "foo" => 1, "bar" => 3 }), s.lengths
89
- assert_equal "bar", s.lengths.first.first
77
+ it "returns a hash of queue and size in order" do
78
+ Sidekiq.redis do |conn|
79
+ conn.rpush 'queue:foo', '{}'
80
+ conn.sadd 'queues', 'foo'
90
81
 
91
- assert_equal Sidekiq::Stats.new.queues, Sidekiq::Stats::Queues.new.lengths
92
- end
93
- end
82
+ 3.times { conn.rpush 'queue:bar', '{}' }
83
+ conn.sadd 'queues', 'bar'
84
+ end
94
85
 
95
- describe "enqueued" do
96
- it "returns total enqueued jobs" do
97
- Sidekiq.redis do |conn|
98
- conn.flushdb
99
- conn.rpush 'queue:foo', '{}'
100
- conn.sadd 'queues', 'foo'
86
+ s = Sidekiq::Stats::Queues.new
87
+ assert_equal ({ "foo" => 1, "bar" => 3 }), s.lengths
88
+ assert_equal "bar", s.lengths.first.first
101
89
 
102
- 3.times { conn.rpush 'queue:bar', '{}' }
103
- conn.sadd 'queues', 'bar'
90
+ assert_equal Sidekiq::Stats.new.queues, Sidekiq::Stats::Queues.new.lengths
104
91
  end
105
-
106
- s = Sidekiq::Stats.new
107
- assert_equal 4, s.enqueued
108
92
  end
109
- end
110
93
 
111
- describe "over time" do
112
- before do
113
- @before = DateTime::DATE_FORMATS[:default]
114
- DateTime::DATE_FORMATS[:default] = "%d/%m/%Y %H:%M:%S"
115
- end
116
-
117
- after do
118
- DateTime::DATE_FORMATS[:default] = @before
119
- end
94
+ describe "enqueued" do
95
+ it "returns total enqueued jobs" do
96
+ Sidekiq.redis do |conn|
97
+ conn.rpush 'queue:foo', '{}'
98
+ conn.sadd 'queues', 'foo'
120
99
 
121
- describe "processed" do
122
- it 'retrieves hash of dates' do
123
- Sidekiq.redis do |c|
124
- c.incrby("stat:processed:2012-12-24", 4)
125
- c.incrby("stat:processed:2012-12-25", 1)
126
- c.incrby("stat:processed:2012-12-26", 6)
127
- c.incrby("stat:processed:2012-12-27", 2)
100
+ 3.times { conn.rpush 'queue:bar', '{}' }
101
+ conn.sadd 'queues', 'bar'
128
102
  end
129
- Time.stub(:now, Time.parse("2012-12-26 1:00:00 -0500")) do
130
- s = Sidekiq::Stats::History.new(2)
131
- assert_equal({ "2012-12-26" => 6, "2012-12-25" => 1 }, s.processed)
132
103
 
133
- s = Sidekiq::Stats::History.new(3)
134
- assert_equal({ "2012-12-26" => 6, "2012-12-25" => 1, "2012-12-24" => 4 }, s.processed)
135
-
136
- s = Sidekiq::Stats::History.new(2, Date.parse("2012-12-25"))
137
- assert_equal({ "2012-12-25" => 1, "2012-12-24" => 4 }, s.processed)
138
- end
104
+ s = Sidekiq::Stats.new
105
+ assert_equal 4, s.enqueued
139
106
  end
140
107
  end
141
108
 
142
- describe "failed" do
143
- it 'retrieves hash of dates' do
144
- Sidekiq.redis do |c|
145
- c.incrby("stat:failed:2012-12-24", 4)
146
- c.incrby("stat:failed:2012-12-25", 1)
147
- c.incrby("stat:failed:2012-12-26", 6)
148
- c.incrby("stat:failed:2012-12-27", 2)
149
- end
150
- Time.stub(:now, Time.parse("2012-12-26 1:00:00 -0500")) do
151
- s = Sidekiq::Stats::History.new(2)
152
- assert_equal ({ "2012-12-26" => 6, "2012-12-25" => 1 }), s.failed
109
+ describe "over time" do
110
+ before do
111
+ require 'active_support/core_ext/time/conversions'
112
+ @before = Time::DATE_FORMATS[:default]
113
+ Time::DATE_FORMATS[:default] = "%d/%m/%Y %H:%M:%S"
114
+ end
153
115
 
154
- s = Sidekiq::Stats::History.new(3)
155
- assert_equal ({ "2012-12-26" => 6, "2012-12-25" => 1, "2012-12-24" => 4 }), s.failed
116
+ after do
117
+ Time::DATE_FORMATS[:default] = @before
118
+ end
156
119
 
157
- s = Sidekiq::Stats::History.new(2, Date.parse("2012-12-25"))
158
- assert_equal ({ "2012-12-25" => 1, "2012-12-24" => 4 }), s.failed
120
+ describe "processed" do
121
+ it 'retrieves hash of dates' do
122
+ Sidekiq.redis do |c|
123
+ c.incrby("stat:processed:2012-12-24", 4)
124
+ c.incrby("stat:processed:2012-12-25", 1)
125
+ c.incrby("stat:processed:2012-12-26", 6)
126
+ c.incrby("stat:processed:2012-12-27", 2)
127
+ end
128
+ Time.stub(:now, Time.parse("2012-12-26 1:00:00 -0500")) do
129
+ s = Sidekiq::Stats::History.new(2)
130
+ assert_equal({ "2012-12-26" => 6, "2012-12-25" => 1 }, s.processed)
131
+
132
+ s = Sidekiq::Stats::History.new(3)
133
+ assert_equal({ "2012-12-26" => 6, "2012-12-25" => 1, "2012-12-24" => 4 }, s.processed)
134
+
135
+ s = Sidekiq::Stats::History.new(2, Date.parse("2012-12-25"))
136
+ assert_equal({ "2012-12-25" => 1, "2012-12-24" => 4 }, s.processed)
137
+ end
159
138
  end
160
139
  end
161
- end
162
- end
163
- end
164
-
165
- describe 'with an empty database' do
166
- before do
167
- Sidekiq.redis {|c| c.flushdb }
168
- end
169
140
 
170
- it 'shows queue as empty' do
171
- q = Sidekiq::Queue.new
172
- assert_equal 0, q.size
173
- assert_equal 0, q.latency
174
- end
175
-
176
- class ApiWorker
177
- include Sidekiq::Worker
141
+ describe "failed" do
142
+ it 'retrieves hash of dates' do
143
+ Sidekiq.redis do |c|
144
+ c.incrby("stat:failed:2012-12-24", 4)
145
+ c.incrby("stat:failed:2012-12-25", 1)
146
+ c.incrby("stat:failed:2012-12-26", 6)
147
+ c.incrby("stat:failed:2012-12-27", 2)
148
+ end
149
+ Time.stub(:now, Time.parse("2012-12-26 1:00:00 -0500")) do
150
+ s = Sidekiq::Stats::History.new(2)
151
+ assert_equal ({ "2012-12-26" => 6, "2012-12-25" => 1 }), s.failed
152
+
153
+ s = Sidekiq::Stats::History.new(3)
154
+ assert_equal ({ "2012-12-26" => 6, "2012-12-25" => 1, "2012-12-24" => 4 }), s.failed
155
+
156
+ s = Sidekiq::Stats::History.new(2, Date.parse("2012-12-25"))
157
+ assert_equal ({ "2012-12-25" => 1, "2012-12-24" => 4 }), s.failed
158
+ end
159
+ end
160
+ end
161
+ end
178
162
  end
179
163
 
180
- it 'can enumerate jobs' do
181
- q = Sidekiq::Queue.new
182
- Time.stub(:now, Time.new(2012, 12, 26)) do
183
- ApiWorker.perform_async(1, 'mike')
184
- assert_equal ['TestApi::ApiWorker'], q.map(&:klass)
185
-
186
- job = q.first
187
- assert_equal 24, job.jid.size
188
- assert_equal [1, 'mike'], job.args
189
- assert_equal Time.new(2012, 12, 26), job.enqueued_at
164
+ describe 'with an empty database' do
165
+ it 'shows queue as empty' do
166
+ q = Sidekiq::Queue.new
167
+ assert_equal 0, q.size
168
+ assert_equal 0, q.latency
190
169
  end
191
170
 
192
- assert q.latency > 10_000_000
193
-
194
- q = Sidekiq::Queue.new('other')
195
- assert_equal 0, q.size
196
- end
171
+ class ApiWorker
172
+ include Sidekiq::Worker
173
+ end
197
174
 
198
- it 'has no enqueued_at time for jobs enqueued in the future' do
199
- job_id = ApiWorker.perform_in(100, 1, 'foo')
200
- job = Sidekiq::ScheduledSet.new.find_job(job_id)
201
- assert_nil job.enqueued_at
202
- end
175
+ it 'can enumerate jobs' do
176
+ q = Sidekiq::Queue.new
177
+ Time.stub(:now, Time.new(2012, 12, 26)) do
178
+ ApiWorker.perform_async(1, 'mike')
179
+ assert_equal ['TestApi::ApiWorker'], q.map(&:klass)
203
180
 
204
- it 'unwraps delayed jobs' do
205
- Sidekiq::Queue.delay.foo(1,2,3)
206
- q = Sidekiq::Queue.new
207
- x = q.first
208
- assert_equal "Sidekiq::Queue.foo", x.display_class
209
- assert_equal [1,2,3], x.display_args
210
- end
181
+ job = q.first
182
+ assert_equal 24, job.jid.size
183
+ assert_equal [1, 'mike'], job.args
184
+ assert_equal Time.new(2012, 12, 26), job.enqueued_at
185
+ end
186
+ assert q.latency > 10_000_000
211
187
 
212
- it 'can delete jobs' do
213
- q = Sidekiq::Queue.new
214
- ApiWorker.perform_async(1, 'mike')
215
- assert_equal 1, q.size
188
+ q = Sidekiq::Queue.new('other')
189
+ assert_equal 0, q.size
190
+ end
216
191
 
217
- x = q.first
218
- assert_equal "TestApi::ApiWorker", x.display_class
219
- assert_equal [1,'mike'], x.display_args
192
+ it 'has no enqueued_at time for jobs enqueued in the future' do
193
+ job_id = ApiWorker.perform_in(100, 1, 'foo')
194
+ job = Sidekiq::ScheduledSet.new.find_job(job_id)
195
+ assert_nil job.enqueued_at
196
+ end
220
197
 
221
- assert_equal [true], q.map(&:delete)
222
- assert_equal 0, q.size
223
- end
198
+ it 'unwraps delayed jobs' do
199
+ Sidekiq::Queue.delay.foo(1,2,3)
200
+ q = Sidekiq::Queue.new
201
+ x = q.first
202
+ assert_equal "Sidekiq::Queue.foo", x.display_class
203
+ assert_equal [1,2,3], x.display_args
204
+ end
224
205
 
225
- it "can move scheduled job to queue" do
226
- remain_id = ApiWorker.perform_in(100, 1, 'jason')
227
- job_id = ApiWorker.perform_in(100, 1, 'jason')
228
- job = Sidekiq::ScheduledSet.new.find_job(job_id)
229
- q = Sidekiq::Queue.new
230
- job.add_to_queue
231
- queued_job = q.find_job(job_id)
232
- refute_nil queued_job
233
- assert_equal queued_job.jid, job_id
234
- assert_nil Sidekiq::ScheduledSet.new.find_job(job_id)
235
- refute_nil Sidekiq::ScheduledSet.new.find_job(remain_id)
236
- end
206
+ it 'has no enqueued_at time for jobs enqueued in the future' do
207
+ job_id = ApiWorker.perform_in(100, 1, 'foo')
208
+ job = Sidekiq::ScheduledSet.new.find_job(job_id)
209
+ assert_nil job.enqueued_at
210
+ end
237
211
 
238
- it "handles multiple scheduled jobs when moving to queue" do
239
- jids = Sidekiq::Client.push_bulk('class' => ApiWorker,
240
- 'args' => [[1, 'jason'], [2, 'jason']],
241
- 'at' => Time.now.to_f)
242
- assert_equal 2, jids.size
243
- (remain_id, job_id) = jids
244
- job = Sidekiq::ScheduledSet.new.find_job(job_id)
245
- q = Sidekiq::Queue.new
246
- job.add_to_queue
247
- queued_job = q.find_job(job_id)
248
- refute_nil queued_job
249
- assert_equal queued_job.jid, job_id
250
- assert_nil Sidekiq::ScheduledSet.new.find_job(job_id)
251
- refute_nil Sidekiq::ScheduledSet.new.find_job(remain_id)
252
- end
212
+ it 'can delete jobs' do
213
+ q = Sidekiq::Queue.new
214
+ ApiWorker.perform_async(1, 'mike')
215
+ assert_equal 1, q.size
253
216
 
254
- it 'can find job by id in sorted sets' do
255
- job_id = ApiWorker.perform_in(100, 1, 'jason')
256
- job = Sidekiq::ScheduledSet.new.find_job(job_id)
257
- refute_nil job
258
- assert_equal job_id, job.jid
259
- assert_in_delta job.latency, 0.0, 0.1
260
- end
217
+ x = q.first
218
+ assert_equal "TestApi::ApiWorker", x.display_class
219
+ assert_equal [1,'mike'], x.display_args
261
220
 
262
- it 'can remove jobs when iterating over a sorted set' do
263
- # scheduled jobs must be greater than SortedSet#each underlying page size
264
- 51.times do
265
- ApiWorker.perform_in(100, 'aaron')
221
+ assert_equal [true], q.map(&:delete)
222
+ assert_equal 0, q.size
266
223
  end
267
- set = Sidekiq::ScheduledSet.new
268
- set.map(&:delete)
269
- assert_equal set.size, 0
270
- end
271
224
 
272
- it 'can remove jobs when iterating over a queue' do
273
- # initial queue size must be greater than Queue#each underlying page size
274
- 51.times do
275
- ApiWorker.perform_async(1, 'aaron')
225
+ it "can move scheduled job to queue" do
226
+ remain_id = ApiWorker.perform_in(100, 1, 'jason')
227
+ job_id = ApiWorker.perform_in(100, 1, 'jason')
228
+ job = Sidekiq::ScheduledSet.new.find_job(job_id)
229
+ q = Sidekiq::Queue.new
230
+ job.add_to_queue
231
+ queued_job = q.find_job(job_id)
232
+ refute_nil queued_job
233
+ assert_equal queued_job.jid, job_id
234
+ assert_nil Sidekiq::ScheduledSet.new.find_job(job_id)
235
+ refute_nil Sidekiq::ScheduledSet.new.find_job(remain_id)
276
236
  end
277
- q = Sidekiq::Queue.new
278
- q.map(&:delete)
279
- assert_equal q.size, 0
280
- end
281
237
 
282
- it 'can find job by id in queues' do
283
- q = Sidekiq::Queue.new
284
- job_id = ApiWorker.perform_async(1, 'jason')
285
- job = q.find_job(job_id)
286
- refute_nil job
287
- assert_equal job_id, job.jid
288
- end
238
+ it "handles multiple scheduled jobs when moving to queue" do
239
+ jids = Sidekiq::Client.push_bulk('class' => ApiWorker,
240
+ 'args' => [[1, 'jason'], [2, 'jason']],
241
+ 'at' => Time.now.to_f)
242
+ assert_equal 2, jids.size
243
+ (remain_id, job_id) = jids
244
+ job = Sidekiq::ScheduledSet.new.find_job(job_id)
245
+ q = Sidekiq::Queue.new
246
+ job.add_to_queue
247
+ queued_job = q.find_job(job_id)
248
+ refute_nil queued_job
249
+ assert_equal queued_job.jid, job_id
250
+ assert_nil Sidekiq::ScheduledSet.new.find_job(job_id)
251
+ refute_nil Sidekiq::ScheduledSet.new.find_job(remain_id)
252
+ end
289
253
 
290
- it 'can clear a queue' do
291
- q = Sidekiq::Queue.new
292
- 2.times { ApiWorker.perform_async(1, 'mike') }
293
- q.clear
254
+ it 'can find job by id in sorted sets' do
255
+ job_id = ApiWorker.perform_in(100, 1, 'jason')
256
+ job = Sidekiq::ScheduledSet.new.find_job(job_id)
257
+ refute_nil job
258
+ assert_equal job_id, job.jid
259
+ assert_in_delta job.latency, 0.0, 0.1
260
+ end
294
261
 
295
- Sidekiq.redis do |conn|
296
- refute conn.smembers('queues').include?('foo')
297
- refute conn.exists('queue:foo')
262
+ it 'can remove jobs when iterating over a sorted set' do
263
+ # scheduled jobs must be greater than SortedSet#each underlying page size
264
+ 51.times do
265
+ ApiWorker.perform_in(100, 'aaron')
266
+ end
267
+ set = Sidekiq::ScheduledSet.new
268
+ set.map(&:delete)
269
+ assert_equal set.size, 0
298
270
  end
299
- end
300
271
 
301
- it 'can fetch by score' do
302
- same_time = Time.now.to_f
303
- add_retry('bob1', same_time)
304
- add_retry('bob2', same_time)
305
- r = Sidekiq::RetrySet.new
306
- assert_equal 2, r.fetch(same_time).size
307
- end
272
+ it 'can remove jobs when iterating over a queue' do
273
+ # initial queue size must be greater than Queue#each underlying page size
274
+ 51.times do
275
+ ApiWorker.perform_async(1, 'aaron')
276
+ end
277
+ q = Sidekiq::Queue.new
278
+ q.map(&:delete)
279
+ assert_equal q.size, 0
280
+ end
308
281
 
309
- it 'can fetch by score and jid' do
310
- same_time = Time.now.to_f
311
- add_retry('bob1', same_time)
312
- add_retry('bob2', same_time)
313
- r = Sidekiq::RetrySet.new
314
- assert_equal 1, r.fetch(same_time, 'bob1').size
315
- end
282
+ it 'can find job by id in queues' do
283
+ q = Sidekiq::Queue.new
284
+ job_id = ApiWorker.perform_async(1, 'jason')
285
+ job = q.find_job(job_id)
286
+ refute_nil job
287
+ assert_equal job_id, job.jid
288
+ end
316
289
 
317
- it 'shows empty retries' do
318
- r = Sidekiq::RetrySet.new
319
- assert_equal 0, r.size
320
- end
290
+ it 'can clear a queue' do
291
+ q = Sidekiq::Queue.new
292
+ 2.times { ApiWorker.perform_async(1, 'mike') }
293
+ q.clear
321
294
 
322
- it 'can enumerate retries' do
323
- add_retry
295
+ Sidekiq.redis do |conn|
296
+ refute conn.smembers('queues').include?('foo')
297
+ refute conn.exists('queue:foo')
298
+ end
299
+ end
324
300
 
325
- r = Sidekiq::RetrySet.new
326
- assert_equal 1, r.size
327
- array = r.to_a
328
- assert_equal 1, array.size
301
+ it 'can fetch by score' do
302
+ same_time = Time.now.to_f
303
+ add_retry('bob1', same_time)
304
+ add_retry('bob2', same_time)
305
+ r = Sidekiq::RetrySet.new
306
+ assert_equal 2, r.fetch(same_time).size
307
+ end
329
308
 
330
- retri = array.first
331
- assert_equal 'ApiWorker', retri.klass
332
- assert_equal 'default', retri.queue
333
- assert_equal 'bob', retri.jid
334
- assert_in_delta Time.now.to_f, retri.at.to_f, 0.02
335
- end
309
+ it 'can fetch by score and jid' do
310
+ same_time = Time.now.to_f
311
+ add_retry('bob1', same_time)
312
+ add_retry('bob2', same_time)
313
+ r = Sidekiq::RetrySet.new
314
+ assert_equal 1, r.fetch(same_time, 'bob1').size
315
+ end
336
316
 
337
- it 'requires a jid to delete an entry' do
338
- start_time = Time.now.to_f
339
- add_retry('bob2', Time.now.to_f)
340
- assert_raises(ArgumentError) do
341
- Sidekiq::RetrySet.new.delete(start_time)
317
+ it 'shows empty retries' do
318
+ r = Sidekiq::RetrySet.new
319
+ assert_equal 0, r.size
342
320
  end
343
- end
344
321
 
345
- it 'can delete a single retry from score and jid' do
346
- same_time = Time.now.to_f
347
- add_retry('bob1', same_time)
348
- add_retry('bob2', same_time)
349
- r = Sidekiq::RetrySet.new
350
- assert_equal 2, r.size
351
- Sidekiq::RetrySet.new.delete(same_time, 'bob1')
352
- assert_equal 1, r.size
353
- end
322
+ it 'can enumerate retries' do
323
+ add_retry
354
324
 
355
- it 'can retry a retry' do
356
- add_retry
357
- r = Sidekiq::RetrySet.new
358
- assert_equal 1, r.size
359
- r.first.retry
360
- assert_equal 0, r.size
361
- assert_equal 1, Sidekiq::Queue.new('default').size
362
- job = Sidekiq::Queue.new('default').first
363
- assert_equal 'bob', job.jid
364
- assert_equal 1, job['retry_count']
365
- end
325
+ r = Sidekiq::RetrySet.new
326
+ assert_equal 1, r.size
327
+ array = r.to_a
328
+ assert_equal 1, array.size
366
329
 
367
- it 'can clear retries' do
368
- add_retry
369
- add_retry('test')
370
- r = Sidekiq::RetrySet.new
371
- assert_equal 2, r.size
372
- r.clear
373
- assert_equal 0, r.size
374
- end
330
+ retri = array.first
331
+ assert_equal 'ApiWorker', retri.klass
332
+ assert_equal 'default', retri.queue
333
+ assert_equal 'bob', retri.jid
334
+ assert_in_delta Time.now.to_f, retri.at.to_f, 0.02
335
+ end
375
336
 
376
- it 'can enumerate processes' do
377
- identity_string = "identity_string"
378
- odata = {
379
- 'pid' => 123,
380
- 'hostname' => Socket.gethostname,
381
- 'key' => identity_string,
382
- 'identity' => identity_string,
383
- 'started_at' => Time.now.to_f - 15,
384
- }
385
-
386
- time = Time.now.to_f
387
- Sidekiq.redis do |conn|
388
- conn.multi do
389
- conn.sadd('processes', odata['key'])
390
- conn.hmset(odata['key'], 'info', Sidekiq.dump_json(odata), 'busy', 10, 'beat', time)
391
- conn.sadd('processes', 'fake:pid')
337
+ it 'requires a jid to delete an entry' do
338
+ start_time = Time.now.to_f
339
+ add_retry('bob2', Time.now.to_f)
340
+ assert_raises(ArgumentError) do
341
+ Sidekiq::RetrySet.new.delete(start_time)
392
342
  end
393
343
  end
394
344
 
395
- ps = Sidekiq::ProcessSet.new.to_a
396
- assert_equal 1, ps.size
397
- data = ps.first
398
- assert_equal 10, data['busy']
399
- assert_equal time, data['beat']
400
- assert_equal 123, data['pid']
401
- data.quiet!
402
- data.stop!
403
- signals_string = "#{odata['key']}-signals"
404
- assert_equal "TERM", Sidekiq.redis{|c| c.lpop(signals_string) }
405
- assert_equal "USR1", Sidekiq.redis{|c| c.lpop(signals_string) }
406
- end
407
-
408
- it 'can enumerate workers' do
409
- w = Sidekiq::Workers.new
410
- assert_equal 0, w.size
411
- w.each do
412
- assert false
345
+ it 'can delete a single retry from score and jid' do
346
+ same_time = Time.now.to_f
347
+ add_retry('bob1', same_time)
348
+ add_retry('bob2', same_time)
349
+ r = Sidekiq::RetrySet.new
350
+ assert_equal 2, r.size
351
+ Sidekiq::RetrySet.new.delete(same_time, 'bob1')
352
+ assert_equal 1, r.size
413
353
  end
414
354
 
415
- hn = Socket.gethostname
416
- key = "#{hn}:#{$$}"
417
- pdata = { 'pid' => $$, 'hostname' => hn, 'started_at' => Time.now.to_i }
418
- Sidekiq.redis do |conn|
419
- conn.sadd('processes', key)
420
- conn.hmset(key, 'info', Sidekiq.dump_json(pdata), 'busy', 0, 'beat', Time.now.to_f)
355
+ it 'can retry a retry' do
356
+ add_retry
357
+ r = Sidekiq::RetrySet.new
358
+ assert_equal 1, r.size
359
+ r.first.retry
360
+ assert_equal 0, r.size
361
+ assert_equal 1, Sidekiq::Queue.new('default').size
362
+ job = Sidekiq::Queue.new('default').first
363
+ assert_equal 'bob', job.jid
364
+ assert_equal 1, job['retry_count']
421
365
  end
422
366
 
423
- s = "#{key}:workers"
424
- data = Sidekiq.dump_json({ 'payload' => {}, 'queue' => 'default', 'run_at' => Time.now.to_i })
425
- Sidekiq.redis do |c|
426
- c.hmset(s, '1234', data)
367
+ it 'can clear retries' do
368
+ add_retry
369
+ add_retry('test')
370
+ r = Sidekiq::RetrySet.new
371
+ assert_equal 2, r.size
372
+ r.clear
373
+ assert_equal 0, r.size
427
374
  end
428
375
 
429
- w.each do |p, x, y|
430
- assert_equal key, p
431
- assert_equal "1234", x
432
- assert_equal 'default', y['queue']
433
- assert_equal Time.now.year, Time.at(y['run_at']).year
376
+ it 'can enumerate processes' do
377
+ identity_string = "identity_string"
378
+ odata = {
379
+ 'pid' => 123,
380
+ 'hostname' => Socket.gethostname,
381
+ 'key' => identity_string,
382
+ 'identity' => identity_string,
383
+ 'started_at' => Time.now.to_f - 15,
384
+ }
385
+
386
+ time = Time.now.to_f
387
+ Sidekiq.redis do |conn|
388
+ conn.multi do
389
+ conn.sadd('processes', odata['key'])
390
+ conn.hmset(odata['key'], 'info', Sidekiq.dump_json(odata), 'busy', 10, 'beat', time)
391
+ conn.sadd('processes', 'fake:pid')
392
+ end
393
+ end
394
+
395
+ ps = Sidekiq::ProcessSet.new.to_a
396
+ assert_equal 1, ps.size
397
+ data = ps.first
398
+ assert_equal 10, data['busy']
399
+ assert_equal time, data['beat']
400
+ assert_equal 123, data['pid']
401
+ data.quiet!
402
+ data.stop!
403
+ signals_string = "#{odata['key']}-signals"
404
+ assert_equal "TERM", Sidekiq.redis{|c| c.lpop(signals_string) }
405
+ assert_equal "USR1", Sidekiq.redis{|c| c.lpop(signals_string) }
434
406
  end
435
407
 
436
- s = "#{key}:workers"
437
- data = Sidekiq.dump_json({ 'payload' => {}, 'queue' => 'default', 'run_at' => (Time.now.to_i - 2*60*60) })
438
- Sidekiq.redis do |c|
439
- c.multi do
440
- c.hmset(s, '5678', data)
441
- c.hmset("b#{s}", '5678', data)
408
+ it 'can enumerate workers' do
409
+ w = Sidekiq::Workers.new
410
+ assert_equal 0, w.size
411
+ w.each do
412
+ assert false
442
413
  end
443
- end
444
414
 
445
- assert_equal ['1234', '5678'], w.map { |_, tid, _| tid }
446
- end
415
+ hn = Socket.gethostname
416
+ key = "#{hn}:#{$$}"
417
+ pdata = { 'pid' => $$, 'hostname' => hn, 'started_at' => Time.now.to_i }
418
+ Sidekiq.redis do |conn|
419
+ conn.sadd('processes', key)
420
+ conn.hmset(key, 'info', Sidekiq.dump_json(pdata), 'busy', 0, 'beat', Time.now.to_f)
421
+ end
447
422
 
448
- it 'can reschedule jobs' do
449
- add_retry('foo1')
450
- add_retry('foo2')
423
+ s = "#{key}:workers"
424
+ data = Sidekiq.dump_json({ 'payload' => {}, 'queue' => 'default', 'run_at' => Time.now.to_i })
425
+ Sidekiq.redis do |c|
426
+ c.hmset(s, '1234', data)
427
+ end
451
428
 
452
- retries = Sidekiq::RetrySet.new
453
- assert_equal 2, retries.size
454
- refute(retries.map { |r| r.score > (Time.now.to_f + 9) }.any?)
429
+ w.each do |p, x, y|
430
+ assert_equal key, p
431
+ assert_equal "1234", x
432
+ assert_equal 'default', y['queue']
433
+ assert_equal Time.now.year, Time.at(y['run_at']).year
434
+ end
455
435
 
456
- retries.each do |retri|
457
- retri.reschedule(Time.now.to_f + 10) if retri.jid == 'foo2'
436
+ s = "#{key}:workers"
437
+ data = Sidekiq.dump_json({ 'payload' => {}, 'queue' => 'default', 'run_at' => (Time.now.to_i - 2*60*60) })
438
+ Sidekiq.redis do |c|
439
+ c.multi do
440
+ c.hmset(s, '5678', data)
441
+ c.hmset("b#{s}", '5678', data)
442
+ end
443
+ end
444
+
445
+ assert_equal ['1234', '5678'], w.map { |_, tid, _| tid }
458
446
  end
459
447
 
460
- assert_equal 2, retries.size
461
- assert(retries.map { |r| r.score > (Time.now.to_f + 9) }.any?)
462
- end
448
+ it 'can reschedule jobs' do
449
+ add_retry('foo1')
450
+ add_retry('foo2')
463
451
 
464
- it 'prunes processes which have died' do
465
- data = { 'pid' => rand(10_000), 'hostname' => "app#{rand(1_000)}", 'started_at' => Time.now.to_f }
466
- key = "#{data['hostname']}:#{data['pid']}"
467
- Sidekiq.redis do |conn|
468
- conn.sadd('processes', key)
469
- conn.hmset(key, 'info', Sidekiq.dump_json(data), 'busy', 0, 'beat', Time.now.to_f)
470
- end
452
+ retries = Sidekiq::RetrySet.new
453
+ assert_equal 2, retries.size
454
+ refute(retries.map { |r| r.score > (Time.now.to_f + 9) }.any?)
471
455
 
472
- ps = Sidekiq::ProcessSet.new
473
- assert_equal 1, ps.size
474
- assert_equal 1, ps.to_a.size
456
+ retries.each do |retri|
457
+ retri.reschedule(Time.now.to_f + 10) if retri.jid == 'foo2'
458
+ end
475
459
 
476
- Sidekiq.redis do |conn|
477
- conn.sadd('processes', "bar:987")
478
- conn.sadd('processes', "bar:986")
460
+ assert_equal 2, retries.size
461
+ assert(retries.map { |r| r.score > (Time.now.to_f + 9) }.any?)
479
462
  end
480
463
 
481
- ps = Sidekiq::ProcessSet.new
482
- assert_equal 1, ps.size
483
- assert_equal 1, ps.to_a.size
484
- end
464
+ it 'prunes processes which have died' do
465
+ data = { 'pid' => rand(10_000), 'hostname' => "app#{rand(1_000)}", 'started_at' => Time.now.to_f }
466
+ key = "#{data['hostname']}:#{data['pid']}"
467
+ Sidekiq.redis do |conn|
468
+ conn.sadd('processes', key)
469
+ conn.hmset(key, 'info', Sidekiq.dump_json(data), 'busy', 0, 'beat', Time.now.to_f)
470
+ end
485
471
 
486
- def add_retry(jid = 'bob', at = Time.now.to_f)
487
- payload = Sidekiq.dump_json('class' => 'ApiWorker', 'args' => [1, 'mike'], 'queue' => 'default', 'jid' => jid, 'retry_count' => 2, 'failed_at' => Time.now.to_f)
488
- Sidekiq.redis do |conn|
489
- conn.zadd('retry', at.to_s, payload)
472
+ ps = Sidekiq::ProcessSet.new
473
+ assert_equal 1, ps.size
474
+ assert_equal 1, ps.to_a.size
475
+
476
+ Sidekiq.redis do |conn|
477
+ conn.sadd('processes', "bar:987")
478
+ conn.sadd('processes', "bar:986")
479
+ end
480
+
481
+ ps = Sidekiq::ProcessSet.new
482
+ assert_equal 1, ps.size
483
+ assert_equal 1, ps.to_a.size
484
+ end
485
+
486
+ def add_retry(jid = 'bob', at = Time.now.to_f)
487
+ payload = Sidekiq.dump_json('class' => 'ApiWorker', 'args' => [1, 'mike'], 'queue' => 'default', 'jid' => jid, 'retry_count' => 2, 'failed_at' => Time.now.to_f)
488
+ Sidekiq.redis do |conn|
489
+ conn.zadd('retry', at.to_s, payload)
490
+ end
490
491
  end
491
492
  end
492
493
  end