sidekiq 3.4.1 → 4.0.0
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.
- checksums.yaml +4 -4
- data/4.0-Upgrade.md +50 -0
- data/COMM-LICENSE +55 -45
- data/Changes.md +73 -1
- data/Ent-Changes.md +66 -0
- data/Gemfile +7 -1
- data/Pro-2.0-Upgrade.md +2 -2
- data/Pro-3.0-Upgrade.md +46 -0
- data/Pro-Changes.md +65 -2
- data/README.md +8 -9
- data/bin/sidekiq +5 -0
- data/bin/sidekiqctl +8 -2
- data/bin/sidekiqload +167 -0
- data/lib/sidekiq/api.rb +29 -31
- data/lib/sidekiq/cli.rb +41 -42
- data/lib/sidekiq/client.rb +5 -10
- data/lib/sidekiq/fetch.rb +35 -111
- data/lib/sidekiq/launcher.rb +102 -42
- data/lib/sidekiq/manager.rb +78 -180
- data/lib/sidekiq/middleware/server/logging.rb +10 -5
- data/lib/sidekiq/middleware/server/retry_jobs.rb +5 -5
- data/lib/sidekiq/processor.rb +126 -97
- data/lib/sidekiq/redis_connection.rb +23 -5
- data/lib/sidekiq/scheduled.rb +47 -26
- data/lib/sidekiq/testing.rb +96 -17
- data/lib/sidekiq/util.rb +20 -0
- data/lib/sidekiq/version.rb +1 -1
- data/lib/sidekiq/web.rb +17 -1
- data/lib/sidekiq/web_helpers.rb +26 -4
- data/lib/sidekiq/worker.rb +14 -0
- data/lib/sidekiq.rb +37 -14
- data/sidekiq.gemspec +11 -11
- data/test/helper.rb +45 -10
- data/test/test_actors.rb +137 -0
- data/test/test_api.rb +388 -388
- data/test/test_cli.rb +29 -59
- data/test/test_client.rb +60 -135
- data/test/test_extensions.rb +29 -23
- data/test/test_fetch.rb +2 -57
- data/test/test_launcher.rb +80 -0
- data/test/test_logging.rb +1 -1
- data/test/test_manager.rb +16 -131
- data/test/test_middleware.rb +3 -5
- data/test/test_processor.rb +110 -76
- data/test/test_rails.rb +21 -0
- data/test/test_redis_connection.rb +0 -1
- data/test/test_retry.rb +114 -162
- data/test/test_scheduled.rb +11 -17
- data/test/test_scheduling.rb +20 -42
- data/test/test_sidekiq.rb +46 -16
- data/test/test_testing.rb +80 -20
- data/test/test_testing_fake.rb +68 -8
- data/test/test_testing_inline.rb +3 -3
- data/test/test_util.rb +16 -0
- data/test/test_web.rb +17 -3
- data/test/test_web_helpers.rb +3 -2
- data/web/assets/images/favicon.ico +0 -0
- data/web/assets/javascripts/application.js +6 -1
- data/web/assets/javascripts/dashboard.js +2 -8
- data/web/assets/javascripts/locales/jquery.timeago.pt-br.js +14 -14
- data/web/assets/stylesheets/application.css +33 -56
- data/web/locales/de.yml +1 -1
- data/web/locales/en.yml +1 -0
- data/web/locales/{no.yml → nb.yml} +10 -2
- data/web/locales/uk.yml +76 -0
- data/web/views/_footer.erb +2 -7
- data/web/views/_job_info.erb +1 -1
- data/web/views/_nav.erb +2 -2
- data/web/views/_poll_js.erb +5 -0
- data/web/views/{_poll.erb → _poll_link.erb} +0 -3
- data/web/views/busy.erb +2 -1
- data/web/views/dead.erb +1 -0
- data/web/views/layout.erb +2 -0
- data/web/views/morgue.erb +3 -0
- data/web/views/queue.erb +1 -0
- data/web/views/queues.erb +1 -0
- data/web/views/retries.erb +3 -0
- data/web/views/retry.erb +1 -0
- data/web/views/scheduled.erb +1 -0
- data/web/views/scheduled_job_info.erb +1 -0
- metadata +81 -47
- data/lib/sidekiq/actor.rb +0 -39
- data/test/test_worker_generator.rb +0 -17
data/test/test_api.rb
CHANGED
@@ -1,493 +1,493 @@
|
|
1
1
|
require_relative 'helper'
|
2
|
+
require 'sidekiq/api'
|
2
3
|
|
3
4
|
class TestApi < Sidekiq::Test
|
4
|
-
|
5
|
-
describe "stats" do
|
5
|
+
describe 'api' do
|
6
6
|
before do
|
7
|
-
Sidekiq.redis = REDIS
|
8
7
|
Sidekiq.redis {|c| c.flushdb }
|
9
8
|
end
|
10
9
|
|
11
|
-
describe "
|
10
|
+
describe "stats" do
|
12
11
|
it "is initially zero" do
|
13
12
|
s = Sidekiq::Stats.new
|
14
13
|
assert_equal 0, s.processed
|
14
|
+
assert_equal 0, s.failed
|
15
|
+
assert_equal 0, s.enqueued
|
15
16
|
end
|
16
17
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
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
|
23
|
+
end
|
21
24
|
end
|
22
|
-
end
|
23
25
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
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
|
28
32
|
end
|
29
33
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
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
|
36
41
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
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
|
42
47
|
end
|
43
|
-
end
|
44
48
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
assert_equal
|
49
|
-
assert_equal
|
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
|
50
54
|
end
|
51
|
-
end
|
52
55
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
assert_equal
|
57
|
-
assert_equal
|
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
|
58
61
|
end
|
59
|
-
end
|
60
62
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
assert_equal
|
65
|
-
assert_equal
|
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
|
66
68
|
end
|
67
69
|
end
|
68
70
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
assert_equal
|
73
|
-
assert_equal '0', conn.get('stat:failed')
|
71
|
+
describe "queues" do
|
72
|
+
it "is initially empty" do
|
73
|
+
s = Sidekiq::Stats::Queues.new
|
74
|
+
assert_equal 0, s.lengths.size
|
74
75
|
end
|
75
|
-
end
|
76
|
-
end
|
77
76
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
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'
|
82
81
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
end
|
82
|
+
3.times { conn.rpush 'queue:bar', '{}' }
|
83
|
+
conn.sadd 'queues', 'bar'
|
84
|
+
end
|
87
85
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
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
|
92
89
|
|
93
|
-
|
94
|
-
conn.sadd 'queues', 'bar'
|
90
|
+
assert_equal Sidekiq::Stats.new.queues, Sidekiq::Stats::Queues.new.lengths
|
95
91
|
end
|
96
|
-
|
97
|
-
s = Sidekiq::Stats::Queues.new
|
98
|
-
assert_equal ({ "foo" => 1, "bar" => 3 }), s.lengths
|
99
|
-
assert_equal "bar", s.lengths.first.first
|
100
92
|
end
|
101
|
-
end
|
102
93
|
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
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'
|
108
99
|
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
conn.sadd 'queues', 'foo'
|
100
|
+
3.times { conn.rpush 'queue:bar', '{}' }
|
101
|
+
conn.sadd 'queues', 'bar'
|
102
|
+
end
|
113
103
|
|
114
|
-
|
115
|
-
|
104
|
+
s = Sidekiq::Stats.new
|
105
|
+
assert_equal 4, s.enqueued
|
116
106
|
end
|
117
|
-
|
118
|
-
s = Sidekiq::Stats.new
|
119
|
-
assert_equal 4, s.enqueued
|
120
107
|
end
|
121
|
-
end
|
122
108
|
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
c.incrby("stat:processed:2012-12-26", 6)
|
130
|
-
c.incrby("stat:processed:2012-12-27", 2)
|
131
|
-
end
|
132
|
-
Time.stub(:now, Time.parse("2012-12-26 1:00:00 -0500")) do
|
133
|
-
s = Sidekiq::Stats::History.new(2)
|
134
|
-
assert_equal ({ "2012-12-26" => 6, "2012-12-25" => 1 }), s.processed
|
135
|
-
|
136
|
-
s = Sidekiq::Stats::History.new(3)
|
137
|
-
assert_equal ({ "2012-12-26" => 6, "2012-12-25" => 1, "2012-12-24" => 4 }), s.processed
|
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
|
138
115
|
|
139
|
-
|
140
|
-
|
141
|
-
end
|
116
|
+
after do
|
117
|
+
Time::DATE_FORMATS[:default] = @before
|
142
118
|
end
|
143
|
-
end
|
144
119
|
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
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
|
152
138
|
end
|
153
|
-
|
154
|
-
s = Sidekiq::Stats::History.new(2)
|
155
|
-
assert_equal ({ "2012-12-26" => 6, "2012-12-25" => 1 }), s.failed
|
156
|
-
|
157
|
-
s = Sidekiq::Stats::History.new(3)
|
158
|
-
assert_equal ({ "2012-12-26" => 6, "2012-12-25" => 1, "2012-12-24" => 4 }), s.failed
|
139
|
+
end
|
159
140
|
|
160
|
-
|
161
|
-
|
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
|
162
159
|
end
|
163
160
|
end
|
164
161
|
end
|
165
162
|
end
|
166
|
-
end
|
167
|
-
|
168
|
-
describe 'with an empty database' do
|
169
|
-
include Sidekiq::Util
|
170
|
-
|
171
|
-
before do
|
172
|
-
Sidekiq.redis = REDIS
|
173
|
-
Sidekiq.redis {|c| c.flushdb }
|
174
|
-
end
|
175
|
-
|
176
|
-
it 'shows queue as empty' do
|
177
|
-
q = Sidekiq::Queue.new
|
178
|
-
assert_equal 0, q.size
|
179
|
-
assert_equal 0, q.latency
|
180
|
-
end
|
181
|
-
|
182
|
-
class ApiWorker
|
183
|
-
include Sidekiq::Worker
|
184
|
-
end
|
185
|
-
|
186
|
-
it 'can enumerate jobs' do
|
187
|
-
q = Sidekiq::Queue.new
|
188
|
-
Time.stub(:now, Time.new(2012, 12, 26)) do
|
189
|
-
ApiWorker.perform_async(1, 'mike')
|
190
|
-
assert_equal ['TestApi::ApiWorker'], q.map(&:klass)
|
191
163
|
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
assert_equal
|
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
|
196
169
|
end
|
197
170
|
|
198
|
-
|
171
|
+
class ApiWorker
|
172
|
+
include Sidekiq::Worker
|
173
|
+
end
|
199
174
|
|
200
|
-
|
201
|
-
|
202
|
-
|
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
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
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
|
-
|
213
|
-
|
214
|
-
|
215
|
-
assert_equal 1, q.size
|
188
|
+
q = Sidekiq::Queue.new('other')
|
189
|
+
assert_equal 0, q.size
|
190
|
+
end
|
216
191
|
|
217
|
-
|
218
|
-
|
219
|
-
|
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
|
-
|
222
|
-
|
223
|
-
|
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
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
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
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
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
|
-
|
255
|
-
|
256
|
-
|
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
|
-
|
263
|
-
|
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
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
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
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
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
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
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
|
-
|
296
|
-
|
297
|
-
|
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
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
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
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
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
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
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
|
-
|
323
|
-
|
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
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
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
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
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
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
r = Sidekiq::RetrySet.new
|
342
|
-
assert_equal 2, r.size
|
343
|
-
Sidekiq::RetrySet.new.delete(same_time)
|
344
|
-
assert_equal 0, r.size
|
345
|
-
end
|
317
|
+
it 'shows empty retries' do
|
318
|
+
r = Sidekiq::RetrySet.new
|
319
|
+
assert_equal 0, r.size
|
320
|
+
end
|
346
321
|
|
347
|
-
|
348
|
-
|
349
|
-
add_retry('bob1', same_time)
|
350
|
-
add_retry('bob2', same_time)
|
351
|
-
r = Sidekiq::RetrySet.new
|
352
|
-
assert_equal 2, r.size
|
353
|
-
Sidekiq::RetrySet.new.delete(same_time, 'bob1')
|
354
|
-
assert_equal 1, r.size
|
355
|
-
end
|
322
|
+
it 'can enumerate retries' do
|
323
|
+
add_retry
|
356
324
|
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
r.first.retry
|
362
|
-
assert_equal 0, r.size
|
363
|
-
assert_equal 1, Sidekiq::Queue.new('default').size
|
364
|
-
job = Sidekiq::Queue.new('default').first
|
365
|
-
assert_equal 'bob', job.jid
|
366
|
-
assert_equal 1, job['retry_count']
|
367
|
-
end
|
325
|
+
r = Sidekiq::RetrySet.new
|
326
|
+
assert_equal 1, r.size
|
327
|
+
array = r.to_a
|
328
|
+
assert_equal 1, array.size
|
368
329
|
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
assert_equal 0, r.size
|
376
|
-
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
|
377
336
|
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
'key' => identity_string,
|
384
|
-
'identity' => identity_string,
|
385
|
-
'started_at' => Time.now.to_f - 15,
|
386
|
-
}
|
387
|
-
|
388
|
-
time = Time.now.to_f
|
389
|
-
Sidekiq.redis do |conn|
|
390
|
-
conn.multi do
|
391
|
-
conn.sadd('processes', odata['key'])
|
392
|
-
conn.hmset(odata['key'], 'info', Sidekiq.dump_json(odata), 'busy', 10, 'beat', time)
|
393
|
-
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)
|
394
342
|
end
|
395
343
|
end
|
396
344
|
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
signals_string = "#{odata['key']}-signals"
|
406
|
-
assert_equal "TERM", Sidekiq.redis{|c| c.lpop(signals_string) }
|
407
|
-
assert_equal "USR1", Sidekiq.redis{|c| c.lpop(signals_string) }
|
408
|
-
end
|
409
|
-
|
410
|
-
it 'can enumerate workers' do
|
411
|
-
w = Sidekiq::Workers.new
|
412
|
-
assert_equal 0, w.size
|
413
|
-
w.each do
|
414
|
-
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
|
415
353
|
end
|
416
354
|
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
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']
|
422
365
|
end
|
423
366
|
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
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
|
428
374
|
end
|
429
375
|
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
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) }
|
435
406
|
end
|
436
407
|
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
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
|
443
413
|
end
|
444
|
-
end
|
445
414
|
|
446
|
-
|
447
|
-
|
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
|
422
|
+
|
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
|
448
428
|
|
449
|
-
|
450
|
-
|
451
|
-
|
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
|
452
435
|
|
453
|
-
|
454
|
-
|
455
|
-
|
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
|
456
444
|
|
457
|
-
|
458
|
-
retri.reschedule(Time.now.to_f + 10) if retri.jid == 'foo2'
|
445
|
+
assert_equal ['1234', '5678'], w.map { |_, tid, _| tid }
|
459
446
|
end
|
460
447
|
|
461
|
-
|
462
|
-
|
463
|
-
|
448
|
+
it 'can reschedule jobs' do
|
449
|
+
add_retry('foo1')
|
450
|
+
add_retry('foo2')
|
464
451
|
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
Sidekiq.redis do |conn|
|
469
|
-
conn.sadd('processes', key)
|
470
|
-
conn.hmset(key, 'info', Sidekiq.dump_json(data), 'busy', 0, 'beat', Time.now.to_f)
|
471
|
-
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?)
|
472
455
|
|
473
|
-
|
474
|
-
|
475
|
-
|
456
|
+
retries.each do |retri|
|
457
|
+
retri.reschedule(Time.now.to_f + 10) if retri.jid == 'foo2'
|
458
|
+
end
|
476
459
|
|
477
|
-
|
478
|
-
|
479
|
-
conn.sadd('processes', "bar:986")
|
460
|
+
assert_equal 2, retries.size
|
461
|
+
assert(retries.map { |r| r.score > (Time.now.to_f + 9) }.any?)
|
480
462
|
end
|
481
463
|
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
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
|
486
471
|
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
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
|
491
491
|
end
|
492
492
|
end
|
493
493
|
end
|