sidekiq 2.12.4 → 2.13.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.
- data/Changes.md +24 -0
- data/README.md +4 -4
- data/lib/sidekiq/api.rb +12 -1
- data/lib/sidekiq/logging.rb +2 -0
- data/lib/sidekiq/middleware/i18n.rb +1 -1
- data/lib/sidekiq/middleware/server/retry_jobs.rb +20 -2
- data/lib/sidekiq/testing.rb +6 -2
- data/lib/sidekiq/util.rb +1 -1
- data/lib/sidekiq/version.rb +1 -1
- data/lib/sidekiq/web.rb +16 -6
- data/lib/sidekiq/worker.rb +19 -2
- data/sidekiq.gemspec +1 -1
- data/test/test_api.rb +12 -0
- data/test/test_retry.rb +102 -15
- data/test/test_testing.rb +31 -0
- data/test/test_util.rb +18 -0
- data/test/test_web.rb +35 -0
- data/web/locales/da.yml +1 -0
- data/web/locales/de.yml +1 -0
- data/web/locales/en.yml +1 -0
- data/web/locales/es.yml +1 -0
- data/web/locales/fr.yml +1 -0
- data/web/locales/it.yml +1 -0
- data/web/locales/ja.yml +1 -0
- data/web/locales/ko.yml +1 -0
- data/web/locales/nl.yml +1 -0
- data/web/locales/no.yml +1 -0
- data/web/locales/pl.yml +1 -0
- data/web/locales/pt-br.yml +1 -0
- data/web/locales/pt.yml +1 -0
- data/web/locales/ru.yml +1 -0
- data/web/views/scheduled.slim +1 -0
- metadata +6 -4
data/Changes.md
CHANGED
@@ -1,3 +1,27 @@
|
|
1
|
+
2.13.0
|
2
|
+
-----------
|
3
|
+
- Adding button to move scheduled job to main queue [guiceolin, #1020]
|
4
|
+
- fix i18n support resetting saved locale when job is retried [#1011]
|
5
|
+
- log rotation via USR2 now closes the old logger [#1008]
|
6
|
+
- Add ability to customize retry schedule, like so [jmazzi, #1027]
|
7
|
+
|
8
|
+
```ruby
|
9
|
+
class MyWorker
|
10
|
+
include Sidekiq::Worker
|
11
|
+
sidekiq_retry_in { |count| count * 2 }
|
12
|
+
end
|
13
|
+
```
|
14
|
+
- Redesign Worker#retries\_exhausted callback to use same form as above [jmazzi, #1030]
|
15
|
+
|
16
|
+
```ruby
|
17
|
+
class MyWorker
|
18
|
+
include Sidekiq::Worker
|
19
|
+
sidekiq_retries_exhausted do |msg|
|
20
|
+
Rails.logger.error "Failed to process #{msg['class']} with args: #{msg['args']}"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
```
|
24
|
+
|
1
25
|
2.12.4
|
2
26
|
-----------
|
3
27
|
|
data/README.md
CHANGED
@@ -4,16 +4,16 @@ Sidekiq
|
|
4
4
|
[![Gem Version](https://badge.fury.io/rb/sidekiq.png)](https://rubygems.org/gems/sidekiq) [![Code Climate](https://codeclimate.com/github/mperham/sidekiq.png)](https://codeclimate.com/github/mperham/sidekiq) [![Build Status](https://travis-ci.org/mperham/sidekiq.png)](https://travis-ci.org/mperham/sidekiq) [![Coverage Status](https://coveralls.io/repos/mperham/sidekiq/badge.png?branch=master)](https://coveralls.io/r/mperham/sidekiq)
|
5
5
|
|
6
6
|
|
7
|
-
Simple, efficient
|
7
|
+
Simple, efficient background processing for Ruby.
|
8
8
|
|
9
|
-
Sidekiq uses threads to handle many
|
9
|
+
Sidekiq uses threads to handle many jobs at the same time in the
|
10
10
|
same process. It does not require Rails but will integrate tightly with
|
11
|
-
Rails 3 to make background
|
11
|
+
Rails 3 to make background processing dead simple.
|
12
12
|
|
13
13
|
Sidekiq is compatible with Resque. It uses the exact same
|
14
14
|
message format as Resque so it can integrate into an existing Resque processing farm.
|
15
15
|
You can have Sidekiq and Resque run side-by-side at the same time and
|
16
|
-
use the Resque client to enqueue
|
16
|
+
use the Resque client to enqueue jobs in Redis to be processed by Sidekiq.
|
17
17
|
|
18
18
|
At the same time, Sidekiq uses multithreading so it is much more memory efficient than
|
19
19
|
Resque (which forks a new process for every job). You'll find that you might need
|
data/lib/sidekiq/api.rb
CHANGED
@@ -139,7 +139,7 @@ module Sidekiq
|
|
139
139
|
def clear
|
140
140
|
Sidekiq.redis do |conn|
|
141
141
|
conn.multi do
|
142
|
-
conn.del(
|
142
|
+
conn.del(@rname)
|
143
143
|
conn.srem("queues", name)
|
144
144
|
end
|
145
145
|
end
|
@@ -222,6 +222,17 @@ module Sidekiq
|
|
222
222
|
@parent.schedule(at, item)
|
223
223
|
end
|
224
224
|
|
225
|
+
def add_to_queue
|
226
|
+
Sidekiq.redis do |conn|
|
227
|
+
results = conn.zrangebyscore('schedule', score, score)
|
228
|
+
conn.zremrangebyscore('schedule', score, score)
|
229
|
+
results.map do |message|
|
230
|
+
msg = Sidekiq.load_json(message)
|
231
|
+
Sidekiq::Client.push(msg)
|
232
|
+
end
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
225
236
|
def retry
|
226
237
|
raise "Retry not available on jobs not in the Retry queue." unless item["failed_at"]
|
227
238
|
Sidekiq.redis do |conn|
|
data/lib/sidekiq/logging.rb
CHANGED
@@ -26,9 +26,11 @@ module Sidekiq
|
|
26
26
|
end
|
27
27
|
|
28
28
|
def self.initialize_logger(log_target = STDOUT)
|
29
|
+
oldlogger = @logger
|
29
30
|
@logger = Logger.new(log_target)
|
30
31
|
@logger.level = Logger::INFO
|
31
32
|
@logger.formatter = Pretty.new
|
33
|
+
oldlogger.close if oldlogger && !$TESTING # don't want to close testing's STDOUT logging
|
32
34
|
@logger
|
33
35
|
end
|
34
36
|
|
@@ -78,7 +78,7 @@ module Sidekiq
|
|
78
78
|
end
|
79
79
|
|
80
80
|
if count < max_retry_attempts
|
81
|
-
delay =
|
81
|
+
delay = delay_for(worker, count)
|
82
82
|
logger.debug { "Failure! Retry #{count} in #{delay} seconds" }
|
83
83
|
retry_at = Time.now.to_f + delay
|
84
84
|
payload = Sidekiq.dump_json(msg)
|
@@ -95,7 +95,12 @@ module Sidekiq
|
|
95
95
|
|
96
96
|
def retries_exhausted(worker, msg)
|
97
97
|
logger.debug { "Dropping message after hitting the retry maximum: #{msg}" }
|
98
|
-
|
98
|
+
if worker.respond_to?(:retries_exhausted)
|
99
|
+
logger.warn { "Defining #{worker.class.name}#retries_exhausted as a method is deprecated, use `sidekiq_retries_exhausted` callback instead http://git.io/Ijju8g" }
|
100
|
+
worker.retries_exhausted(*msg['args'])
|
101
|
+
elsif worker.sidekiq_retries_exhausted_block?
|
102
|
+
worker.sidekiq_retries_exhausted_block.call(msg)
|
103
|
+
end
|
99
104
|
|
100
105
|
rescue Exception => e
|
101
106
|
handle_exception(e, "Error calling retries_exhausted")
|
@@ -109,11 +114,24 @@ module Sidekiq
|
|
109
114
|
end
|
110
115
|
end
|
111
116
|
|
117
|
+
def delay_for(worker, count)
|
118
|
+
worker.sidekiq_retry_in_block? && retry_in(worker, count) || seconds_to_delay(count)
|
119
|
+
end
|
120
|
+
|
112
121
|
# delayed_job uses the same basic formula
|
113
122
|
def seconds_to_delay(count)
|
114
123
|
(count ** 4) + 15 + (rand(30)*(count+1))
|
115
124
|
end
|
116
125
|
|
126
|
+
def retry_in(worker, count)
|
127
|
+
begin
|
128
|
+
worker.sidekiq_retry_in_block.call(count)
|
129
|
+
rescue Exception => e
|
130
|
+
logger.error { "Failure scheduling retry using the defined `sidekiq_retry_in` in #{worker.class.name}, falling back to default: #{e.message}"}
|
131
|
+
nil
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
117
135
|
end
|
118
136
|
end
|
119
137
|
end
|
data/lib/sidekiq/testing.rb
CHANGED
@@ -86,7 +86,9 @@ module Sidekiq
|
|
86
86
|
# Drain and run all jobs for this worker
|
87
87
|
def drain
|
88
88
|
while job = jobs.shift do
|
89
|
-
new
|
89
|
+
worker = new
|
90
|
+
worker.jid = job['jid']
|
91
|
+
worker.perform(*job['args'])
|
90
92
|
end
|
91
93
|
end
|
92
94
|
|
@@ -94,7 +96,9 @@ module Sidekiq
|
|
94
96
|
def perform_one
|
95
97
|
raise(EmptyQueueError, "perform_one called with empty job queue") if jobs.empty?
|
96
98
|
job = jobs.shift
|
97
|
-
new
|
99
|
+
worker = new
|
100
|
+
worker.jid = job['jid']
|
101
|
+
worker.perform(*job['args'])
|
98
102
|
end
|
99
103
|
end
|
100
104
|
|
data/lib/sidekiq/util.rb
CHANGED
data/lib/sidekiq/version.rb
CHANGED
data/lib/sidekiq/web.rb
CHANGED
@@ -41,7 +41,13 @@ module Sidekiq
|
|
41
41
|
def reset_worker_list
|
42
42
|
Sidekiq.redis do |conn|
|
43
43
|
workers = conn.smembers('workers')
|
44
|
-
conn.srem('workers',
|
44
|
+
conn.srem('workers', workers) if !workers.empty?
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def workers_size
|
49
|
+
Sidekiq.redis do |conn|
|
50
|
+
conn.scard('workers')
|
45
51
|
end
|
46
52
|
end
|
47
53
|
|
@@ -84,7 +90,7 @@ module Sidekiq
|
|
84
90
|
end
|
85
91
|
|
86
92
|
def current_status
|
87
|
-
return 'idle' if
|
93
|
+
return 'idle' if workers_size == 0
|
88
94
|
return 'active'
|
89
95
|
end
|
90
96
|
|
@@ -245,9 +251,14 @@ module Sidekiq
|
|
245
251
|
|
246
252
|
post '/scheduled' do
|
247
253
|
halt 404 unless params['key']
|
248
|
-
|
254
|
+
|
249
255
|
params['key'].each do |key|
|
250
|
-
Sidekiq::ScheduledSet.new.fetch(*parse_params(key)).first
|
256
|
+
job = Sidekiq::ScheduledSet.new.fetch(*parse_params(key)).first
|
257
|
+
if params['delete']
|
258
|
+
job.delete
|
259
|
+
elsif params['add_to_queue']
|
260
|
+
job.add_to_queue
|
261
|
+
end
|
251
262
|
end
|
252
263
|
redirect "#{root_path}scheduled"
|
253
264
|
end
|
@@ -269,7 +280,7 @@ module Sidekiq
|
|
269
280
|
sidekiq: {
|
270
281
|
processed: sidekiq_stats.processed,
|
271
282
|
failed: sidekiq_stats.failed,
|
272
|
-
busy:
|
283
|
+
busy: workers_size,
|
273
284
|
enqueued: sidekiq_stats.enqueued,
|
274
285
|
scheduled: sidekiq_stats.scheduled_size,
|
275
286
|
retries: sidekiq_stats.retry_size,
|
@@ -285,4 +296,3 @@ module Sidekiq
|
|
285
296
|
end
|
286
297
|
|
287
298
|
end
|
288
|
-
|
data/lib/sidekiq/worker.rb
CHANGED
@@ -26,6 +26,8 @@ module Sidekiq
|
|
26
26
|
def self.included(base)
|
27
27
|
base.extend(ClassMethods)
|
28
28
|
base.class_attribute :sidekiq_options_hash
|
29
|
+
base.class_attribute :sidekiq_retry_in_block
|
30
|
+
base.class_attribute :sidekiq_retries_exhausted_block
|
29
31
|
end
|
30
32
|
|
31
33
|
def logger
|
@@ -40,8 +42,15 @@ module Sidekiq
|
|
40
42
|
|
41
43
|
def perform_in(interval, *args)
|
42
44
|
int = interval.to_f
|
43
|
-
|
44
|
-
|
45
|
+
now = Time.now.to_f
|
46
|
+
ts = (int < 1_000_000_000 ? now + int : int)
|
47
|
+
|
48
|
+
# Optimization to enqueue something now that is scheduled to go out now or in the past
|
49
|
+
if ts <= now
|
50
|
+
perform_async(*args)
|
51
|
+
else
|
52
|
+
client_push('class' => self, 'args' => args, 'at' => ts)
|
53
|
+
end
|
45
54
|
end
|
46
55
|
alias_method :perform_at, :perform_in
|
47
56
|
|
@@ -58,6 +67,14 @@ module Sidekiq
|
|
58
67
|
::Sidekiq.logger.warn("#{self.name} - :timeout is unsafe and support has been removed from Sidekiq, see http://bit.ly/OtYpK for details") if opts.include? :timeout
|
59
68
|
end
|
60
69
|
|
70
|
+
def sidekiq_retry_in(&block)
|
71
|
+
self.sidekiq_retry_in_block = block
|
72
|
+
end
|
73
|
+
|
74
|
+
def sidekiq_retries_exhausted(&block)
|
75
|
+
self.sidekiq_retries_exhausted_block = block
|
76
|
+
end
|
77
|
+
|
61
78
|
DEFAULT_OPTIONS = { 'retry' => true, 'queue' => 'default' }
|
62
79
|
|
63
80
|
def get_sidekiq_options # :nodoc:
|
data/sidekiq.gemspec
CHANGED
@@ -4,7 +4,7 @@ require File.expand_path('../lib/sidekiq/version', __FILE__)
|
|
4
4
|
Gem::Specification.new do |gem|
|
5
5
|
gem.authors = ["Mike Perham"]
|
6
6
|
gem.email = ["mperham@gmail.com"]
|
7
|
-
gem.description = gem.summary = "Simple, efficient
|
7
|
+
gem.description = gem.summary = "Simple, efficient background processing for Ruby"
|
8
8
|
gem.homepage = "http://sidekiq.org"
|
9
9
|
gem.license = "LGPL-3.0"
|
10
10
|
|
data/test/test_api.rb
CHANGED
@@ -172,6 +172,18 @@ class TestApi < Minitest::Test
|
|
172
172
|
assert_equal 0, q.size
|
173
173
|
end
|
174
174
|
|
175
|
+
it "can move scheduled job to queue" do
|
176
|
+
job_id = ApiWorker.perform_in(100, 1, 'jason')
|
177
|
+
job = Sidekiq::ScheduledSet.new.find_job(job_id)
|
178
|
+
q = Sidekiq::Queue.new
|
179
|
+
job.add_to_queue
|
180
|
+
queued_job = q.find_job(job_id)
|
181
|
+
refute_nil queued_job
|
182
|
+
assert_equal queued_job.jid, job_id
|
183
|
+
job = Sidekiq::ScheduledSet.new.find_job(job_id)
|
184
|
+
assert_nil job
|
185
|
+
end
|
186
|
+
|
175
187
|
it 'can find job by id in sorted sets' do
|
176
188
|
job_id = ApiWorker.perform_in(100, 1, 'jason')
|
177
189
|
job = Sidekiq::ScheduledSet.new.find_job(job_id)
|
data/test/test_retry.rb
CHANGED
@@ -12,12 +12,18 @@ class TestRetry < Minitest::Test
|
|
12
12
|
def @redis.with; yield self; end
|
13
13
|
end
|
14
14
|
|
15
|
+
let(:worker) do
|
16
|
+
Class.new do
|
17
|
+
include ::Sidekiq::Worker
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
15
21
|
it 'allows disabling retry' do
|
16
22
|
msg = { 'class' => 'Bob', 'args' => [1,2,'foo'], 'retry' => false }
|
17
23
|
msg2 = msg.dup
|
18
24
|
handler = Sidekiq::Middleware::Server::RetryJobs.new
|
19
25
|
assert_raises RuntimeError do
|
20
|
-
handler.call(
|
26
|
+
handler.call(worker, msg2, 'default') do
|
21
27
|
raise "kerblammo!"
|
22
28
|
end
|
23
29
|
end
|
@@ -30,7 +36,7 @@ class TestRetry < Minitest::Test
|
|
30
36
|
msg2 = msg.dup
|
31
37
|
handler = Sidekiq::Middleware::Server::RetryJobs.new
|
32
38
|
assert_raises RuntimeError do
|
33
|
-
handler.call(
|
39
|
+
handler.call(worker, msg2, 'default') do
|
34
40
|
raise "kerblammo!"
|
35
41
|
end
|
36
42
|
end
|
@@ -45,7 +51,7 @@ class TestRetry < Minitest::Test
|
|
45
51
|
handler = Sidekiq::Middleware::Server::RetryJobs.new
|
46
52
|
c = nil
|
47
53
|
assert_raises RuntimeError do
|
48
|
-
handler.call(
|
54
|
+
handler.call(worker, msg, 'default') do
|
49
55
|
c = caller(0); raise "kerblammo!"
|
50
56
|
end
|
51
57
|
end
|
@@ -60,7 +66,7 @@ class TestRetry < Minitest::Test
|
|
60
66
|
handler = Sidekiq::Middleware::Server::RetryJobs.new
|
61
67
|
c = nil
|
62
68
|
assert_raises RuntimeError do
|
63
|
-
handler.call(
|
69
|
+
handler.call(worker, msg, 'default') do
|
64
70
|
c = caller(0)[0..3]; raise "kerblammo!"
|
65
71
|
end
|
66
72
|
end
|
@@ -73,7 +79,7 @@ class TestRetry < Minitest::Test
|
|
73
79
|
msg = { 'class' => 'Bob', 'args' => [1,2,'foo'], 'retry' => true }
|
74
80
|
handler = Sidekiq::Middleware::Server::RetryJobs.new
|
75
81
|
assert_raises RuntimeError do
|
76
|
-
handler.call(
|
82
|
+
handler.call(worker, msg, 'default') do
|
77
83
|
raise "kerblammo!"
|
78
84
|
end
|
79
85
|
end
|
@@ -91,7 +97,7 @@ class TestRetry < Minitest::Test
|
|
91
97
|
msg = { 'class' => 'Bob', 'args' => [1,2,'foo'], 'retry' => true, 'retry_queue' => 'retry' }
|
92
98
|
handler = Sidekiq::Middleware::Server::RetryJobs.new
|
93
99
|
assert_raises RuntimeError do
|
94
|
-
handler.call(
|
100
|
+
handler.call(worker, msg, 'default') do
|
95
101
|
raise "kerblammo!"
|
96
102
|
end
|
97
103
|
end
|
@@ -110,7 +116,7 @@ class TestRetry < Minitest::Test
|
|
110
116
|
msg = {"class"=>"Bob", "args"=>[1, 2, "foo"], 'retry' => true, "queue"=>"default", "error_message"=>"kerblammo!", "error_class"=>"RuntimeError", "failed_at"=>now, "retry_count"=>10}
|
111
117
|
handler = Sidekiq::Middleware::Server::RetryJobs.new
|
112
118
|
assert_raises RuntimeError do
|
113
|
-
handler.call(
|
119
|
+
handler.call(worker, msg, 'default') do
|
114
120
|
raise "kerblammo!"
|
115
121
|
end
|
116
122
|
end
|
@@ -128,7 +134,7 @@ class TestRetry < Minitest::Test
|
|
128
134
|
msg = {"class"=>"Bob", "args"=>[1, 2, "foo"], 'retry' => 10, "queue"=>"default", "error_message"=>"kerblammo!", "error_class"=>"RuntimeError", "failed_at"=>now, "retry_count"=>8}
|
129
135
|
handler = Sidekiq::Middleware::Server::RetryJobs.new
|
130
136
|
assert_raises RuntimeError do
|
131
|
-
handler.call(
|
137
|
+
handler.call(worker, msg, 'default') do
|
132
138
|
raise "kerblammo!"
|
133
139
|
end
|
134
140
|
end
|
@@ -146,7 +152,7 @@ class TestRetry < Minitest::Test
|
|
146
152
|
@redis.expect :zadd, 1, [ 'retry', String, String ]
|
147
153
|
handler = Sidekiq::Middleware::Server::RetryJobs.new
|
148
154
|
assert_raises RuntimeError do
|
149
|
-
handler.call(
|
155
|
+
handler.call(worker, msg, 'default') do
|
150
156
|
raise "kerblammo!"
|
151
157
|
end
|
152
158
|
end
|
@@ -160,7 +166,7 @@ class TestRetry < Minitest::Test
|
|
160
166
|
@redis.expect :zadd, 1, [ 'retry', String, String ]
|
161
167
|
handler = Sidekiq::Middleware::Server::RetryJobs.new
|
162
168
|
assert_raises RuntimeError do
|
163
|
-
handler.call(
|
169
|
+
handler.call(worker, msg, 'default') do
|
164
170
|
raise "kerblammo!"
|
165
171
|
end
|
166
172
|
end
|
@@ -169,14 +175,45 @@ class TestRetry < Minitest::Test
|
|
169
175
|
end
|
170
176
|
|
171
177
|
describe "retry exhaustion" do
|
172
|
-
let(:worker){ Minitest::Mock.new }
|
173
178
|
let(:handler){ Sidekiq::Middleware::Server::RetryJobs.new }
|
179
|
+
let(:worker) { Minitest::Mock.new }
|
174
180
|
let(:msg){ {"class"=>"Bob", "args"=>[1, 2, "foo"], "queue"=>"default", "error_message"=>"kerblammo!", "error_class"=>"RuntimeError", "failed_at"=>Time.now.utc, "retry"=>3, "retry_count"=>3} }
|
175
181
|
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
182
|
+
describe "worker method" do
|
183
|
+
let(:worker) do
|
184
|
+
klass = Class.new do
|
185
|
+
include Sidekiq::Worker
|
186
|
+
|
187
|
+
def self.name; "Worker"; end
|
188
|
+
|
189
|
+
def retries_exhausted(*args)
|
190
|
+
args << "retried_method"
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
it 'calls worker.retries_exhausted after too many retries' do
|
196
|
+
assert_equal [1,2, "foo", "retried_method"], handler.retries_exhausted(worker.new, msg)
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
describe "worker block" do
|
201
|
+
let(:worker) do
|
202
|
+
Class.new do
|
203
|
+
include Sidekiq::Worker
|
204
|
+
|
205
|
+
sidekiq_retries_exhausted do |msg|
|
206
|
+
msg.tap {|m| m['called_by_callback'] = true }
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
it 'calls worker sidekiq_retries_exhausted_block after too many retries' do
|
212
|
+
new_msg = handler.retries_exhausted(worker.new, msg)
|
213
|
+
expected_msg = msg.merge('called_by_callback' => true)
|
214
|
+
|
215
|
+
assert_equal expected_msg, new_msg, "sidekiq_retries_exhausted block not called"
|
216
|
+
end
|
180
217
|
end
|
181
218
|
|
182
219
|
it 'handles and logs retries_exhausted failures gracefully (drops them)' do
|
@@ -197,6 +234,56 @@ class TestRetry < Minitest::Test
|
|
197
234
|
end
|
198
235
|
end
|
199
236
|
end
|
237
|
+
|
238
|
+
describe "custom retry delay" do
|
239
|
+
before do
|
240
|
+
@old_logger = Sidekiq.logger
|
241
|
+
@tmp_log_path = '/tmp/sidekiq-retries.log'
|
242
|
+
Sidekiq.logger = Logger.new(@tmp_log_path)
|
243
|
+
end
|
244
|
+
|
245
|
+
after do
|
246
|
+
Sidekiq.logger = @old_logger
|
247
|
+
Sidekiq.options.delete(:logfile)
|
248
|
+
File.unlink @tmp_log_path if File.exists?(@tmp_log_path)
|
249
|
+
end
|
250
|
+
|
251
|
+
let(:custom_worker) do
|
252
|
+
Class.new do
|
253
|
+
include ::Sidekiq::Worker
|
254
|
+
|
255
|
+
sidekiq_retry_in do |count|
|
256
|
+
count * 2
|
257
|
+
end
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
let(:error_worker) do
|
262
|
+
Class.new do
|
263
|
+
include ::Sidekiq::Worker
|
264
|
+
|
265
|
+
sidekiq_retry_in do |count|
|
266
|
+
count / 0
|
267
|
+
end
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
let(:handler) { Sidekiq::Middleware::Server::RetryJobs.new }
|
272
|
+
|
273
|
+
it "retries with a default delay" do
|
274
|
+
refute_equal 4, handler.delay_for(worker, 2)
|
275
|
+
end
|
276
|
+
|
277
|
+
it "retries with a custom delay" do
|
278
|
+
assert_equal 4, handler.delay_for(custom_worker, 2)
|
279
|
+
end
|
280
|
+
|
281
|
+
it "falls back to the default retry on exception" do
|
282
|
+
refute_equal 4, handler.delay_for(error_worker, 2)
|
283
|
+
assert_match(/Failure scheduling retry using the defined `sidekiq_retry_in`/,
|
284
|
+
File.read(@tmp_log_path), 'Log entry missing for sidekiq_retry_in')
|
285
|
+
end
|
286
|
+
end
|
200
287
|
end
|
201
288
|
|
202
289
|
end
|
data/test/test_testing.rb
CHANGED
@@ -49,6 +49,7 @@ class TestTesting < Minitest::Test
|
|
49
49
|
before do
|
50
50
|
load 'sidekiq/testing.rb'
|
51
51
|
EnqueuedWorker.jobs.clear
|
52
|
+
DirectWorker.jobs.clear
|
52
53
|
end
|
53
54
|
|
54
55
|
after do
|
@@ -112,6 +113,36 @@ class TestTesting < Minitest::Test
|
|
112
113
|
|
113
114
|
end
|
114
115
|
|
116
|
+
class SpecificJidWorker
|
117
|
+
include Sidekiq::Worker
|
118
|
+
class_attribute :count
|
119
|
+
self.count = 0
|
120
|
+
def perform(worker_jid)
|
121
|
+
return unless worker_jid == self.jid
|
122
|
+
self.class.count += 1
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
it 'execute only jobs with assigned JID' do
|
127
|
+
4.times do |i|
|
128
|
+
jid = SpecificJidWorker.perform_async(nil)
|
129
|
+
if i % 2 == 0
|
130
|
+
SpecificJidWorker.jobs[-1]["args"] = ["wrong_jid"]
|
131
|
+
else
|
132
|
+
SpecificJidWorker.jobs[-1]["args"] = [jid]
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
SpecificJidWorker.perform_one
|
137
|
+
assert_equal 0, SpecificJidWorker.count
|
138
|
+
|
139
|
+
SpecificJidWorker.perform_one
|
140
|
+
assert_equal 1, SpecificJidWorker.count
|
141
|
+
|
142
|
+
SpecificJidWorker.drain
|
143
|
+
assert_equal 2, SpecificJidWorker.count
|
144
|
+
end
|
145
|
+
|
115
146
|
it 'round trip serializes the job arguments' do
|
116
147
|
assert StoredWorker.perform_async(:mike)
|
117
148
|
job = StoredWorker.jobs.first
|
data/test/test_util.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'helper'
|
2
|
+
require 'sidekiq/util'
|
3
|
+
|
4
|
+
class TestUtil < Minitest::Test
|
5
|
+
describe 'util' do
|
6
|
+
it 'generates the same process id when included in two or more classes' do
|
7
|
+
class One
|
8
|
+
include Sidekiq::Util
|
9
|
+
end
|
10
|
+
|
11
|
+
class Two
|
12
|
+
include Sidekiq::Util
|
13
|
+
end
|
14
|
+
|
15
|
+
assert_equal One.new.process_id, Two.new.process_id
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
data/test/test_web.rb
CHANGED
@@ -76,6 +76,26 @@ class TestWeb < Minitest::Test
|
|
76
76
|
end
|
77
77
|
end
|
78
78
|
|
79
|
+
it 'can clear an empty worker list' do
|
80
|
+
post '/reset'
|
81
|
+
assert_equal 302, last_response.status
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'can clear a non-empty worker list' do
|
85
|
+
Sidekiq.redis do |conn|
|
86
|
+
identity = 'foo'
|
87
|
+
conn.sadd('workers', identity)
|
88
|
+
end
|
89
|
+
|
90
|
+
post '/reset'
|
91
|
+
|
92
|
+
assert_equal 302, last_response.status
|
93
|
+
|
94
|
+
Sidekiq.redis do |conn|
|
95
|
+
refute conn.smembers('workers').any?
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
79
99
|
it 'can delete a job' do
|
80
100
|
Sidekiq.redis do |conn|
|
81
101
|
conn.rpush('queue:foo', "{}")
|
@@ -178,6 +198,21 @@ class TestWeb < Minitest::Test
|
|
178
198
|
end
|
179
199
|
end
|
180
200
|
|
201
|
+
it "can move scheduled to default queue" do
|
202
|
+
params = add_scheduled
|
203
|
+
Sidekiq.redis do |conn|
|
204
|
+
assert_equal 1, conn.zcard('schedule')
|
205
|
+
assert_equal 0, conn.zcard('default')
|
206
|
+
post '/scheduled', 'key' => [job_params(*params)], 'add_to_queue' => 'AddToQueue'
|
207
|
+
assert_equal 302, last_response.status
|
208
|
+
assert_equal 'http://example.org/scheduled', last_response.header['Location']
|
209
|
+
assert_equal 0, conn.zcard('schedule')
|
210
|
+
get '/queues/default'
|
211
|
+
assert_equal 200, last_response.status
|
212
|
+
assert_match /#{params[0]['args'][2]}/, last_response.body
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
181
216
|
it 'can retry all retries' do
|
182
217
|
msg, score = add_retry
|
183
218
|
add_retry
|
data/web/locales/da.yml
CHANGED
@@ -24,6 +24,7 @@ da:
|
|
24
24
|
ShowAll: Vis alle
|
25
25
|
CurrentMessagesInQueue: Nuværende beskeder i <span class='title'>%{queue}</span>
|
26
26
|
Delete: Slet
|
27
|
+
AddToQueue: Tilføj til kø
|
27
28
|
AreYouSureDeleteJob: Er du sikker på at du vil slette dette job?
|
28
29
|
AreYouSureDeleteQueue: Er du sikker på at du vil slette %{queue} køen?
|
29
30
|
Queues: Køer
|
data/web/locales/de.yml
CHANGED
@@ -24,6 +24,7 @@ de:
|
|
24
24
|
ShowAll: Alle anzeigen
|
25
25
|
CurrentMessagesInQueue: Aktuelle Nachrichten in <span class='title'>%{queue}</span>
|
26
26
|
Delete: Löschen
|
27
|
+
AddToQueue: Add to queue
|
27
28
|
AreYouSureDeleteJob: Möchtest du diesen Job wirklich löschen?
|
28
29
|
AreYouSureDeleteQueue: Möchtest du %{queue} wirklich löschen?
|
29
30
|
Queues: Warteschlangen
|
data/web/locales/en.yml
CHANGED
@@ -26,6 +26,7 @@ en: # <---- change this to your locale code
|
|
26
26
|
ShowAll: Show All
|
27
27
|
CurrentMessagesInQueue: Current messages in <span class='title'>%{queue}</span>
|
28
28
|
Delete: Delete
|
29
|
+
AddToQueue: Add to queue
|
29
30
|
AreYouSureDeleteJob: Are you sure you want to delete this job?
|
30
31
|
AreYouSureDeleteQueue: Are you sure you want to delete the %{queue} queue?
|
31
32
|
Queues: Queues
|
data/web/locales/es.yml
CHANGED
@@ -24,6 +24,7 @@ es:
|
|
24
24
|
ShowAll: Mostrar Todo
|
25
25
|
CurrentMessagesInQueue: Mensajes actualmente en <span class='title'>%{queue}</span>
|
26
26
|
Delete: Eliminar
|
27
|
+
AddToQueue: Añadir a fila
|
27
28
|
AreYouSureDeleteJob: ¿Estás seguro de eliminar este trabajo?
|
28
29
|
AreYouSureDeleteQueue: ¿Estás seguro de eliminar la fila %{queue}?
|
29
30
|
Queues: Filas
|
data/web/locales/fr.yml
CHANGED
@@ -24,6 +24,7 @@ fr:
|
|
24
24
|
ShowAll: Montrer Tout
|
25
25
|
CurrentMessagesInQueue: Messages actuellement dans <span class='title'>%{queue}</span>
|
26
26
|
Delete: Supprimer
|
27
|
+
AddToQueue: Ajouter à la liste
|
27
28
|
AreYouSureDeleteJob: Êtes-vous certain de vouloir supprimer cette tâche?
|
28
29
|
AreYouSureDeleteQueue: Êtes-vous certain de vouloir supprimer la file %{queue}?
|
29
30
|
Queues: Queues
|
data/web/locales/it.yml
CHANGED
@@ -24,6 +24,7 @@ it:
|
|
24
24
|
ShowAll: Mostra tutti
|
25
25
|
CurrentMessagesInQueue: Messaggi in <span class='title'>%{queue}</span>
|
26
26
|
Delete: Cancella
|
27
|
+
AddToQueue: Aggiungi a coda
|
27
28
|
AreYouSureDeleteJob: Sei sicuro di voler cancellare questo lavoro?
|
28
29
|
AreYouSureDeleteQueue: Sei sicuro di voler cancellare la coda %{queue}?
|
29
30
|
Queues: Code
|
data/web/locales/ja.yml
CHANGED
data/web/locales/ko.yml
CHANGED
data/web/locales/nl.yml
CHANGED
@@ -25,6 +25,7 @@ nl:
|
|
25
25
|
ShowAll: Toon alle
|
26
26
|
CurrentMessagesInQueue: Aantal berichten in <span class='title'>%{queue}</span>
|
27
27
|
Delete: Verwijderen
|
28
|
+
AddToQueue: Toevoegen aan wachtrij
|
28
29
|
AreYouSureDeleteJob: Weet u zeker dat u deze taak wilt verwijderen?
|
29
30
|
AreYouSureDeleteQueue: Weet u zeker dat u wachtrij %{queue} wilt verwijderen?
|
30
31
|
Queues: Wachtrijen
|
data/web/locales/no.yml
CHANGED
@@ -25,6 +25,7 @@ no:
|
|
25
25
|
ShowAll: Vis alle
|
26
26
|
CurrentMessagesInQueue: Nåværende melding i <span class='title'>%{queue}</span>
|
27
27
|
Delete: Slett
|
28
|
+
AddToQueue: Legg til i kø
|
28
29
|
AreYouSureDeleteJob: Er du sikker på at du vil slette denne jobben?
|
29
30
|
AreYouSureDeleteQueue: Er du sikker på at du vil slette køen %{queue}?
|
30
31
|
Queues: Køer
|
data/web/locales/pl.yml
CHANGED
@@ -24,6 +24,7 @@ pl:
|
|
24
24
|
ShowAll: Pokaż wszystko
|
25
25
|
CurrentMessagesInQueue: Aktualne wiadomości w kolejce <span class='title'>%{queue}</span>
|
26
26
|
Delete: Usuń
|
27
|
+
AddToQueue: dodaj do kolejki
|
27
28
|
AreYouSureDeleteJob: Czy na pewno usunąć to zadanie?
|
28
29
|
AreYouSureDeleteQueue: Czy na pewno usunąć kolejkę %{queue}?
|
29
30
|
Queues: Kolejki
|
data/web/locales/pt-br.yml
CHANGED
@@ -25,6 +25,7 @@
|
|
25
25
|
ShowAll: Mostrar todos
|
26
26
|
CurrentMessagesInQueue: Mensagens atualmenta na <span class='title'>%{queue}</span>
|
27
27
|
Delete: Apagar
|
28
|
+
AddToQueue: Adicionar à fila
|
28
29
|
AreYouSureDeleteJob: Deseja deletar esta tarefa?
|
29
30
|
AreYouSureDeleteQueue: Deseja deletar a %{queue} fila?
|
30
31
|
Queues: Filas
|
data/web/locales/pt.yml
CHANGED
@@ -24,6 +24,7 @@ pt:
|
|
24
24
|
ShowAll: Mostrar todos
|
25
25
|
CurrentMessagesInQueue: Mensagens na fila <span class='title'>%{queue}</span>
|
26
26
|
Delete: Apagar
|
27
|
+
AddToQueue: Adicionar à fila
|
27
28
|
AreYouSureDeleteJob: Tem a certeza que deseja eliminar esta tarefa?
|
28
29
|
AreYouSureDeleteQueue: Tem a certeza que deseja eliminar a fila %{queue}?
|
29
30
|
Queues: Filas
|
data/web/locales/ru.yml
CHANGED
@@ -24,6 +24,7 @@ ru:
|
|
24
24
|
ShowAll: Показать все
|
25
25
|
CurrentMessagesInQueue: Текущие сообщения в <span class='title'>%{queue}</span>
|
26
26
|
Delete: Удалить
|
27
|
+
AddToQueue: Добавить в очередь
|
27
28
|
AreYouSureDeleteJob: Вы уверены в том, что хотите удалить задание?
|
28
29
|
AreYouSureDeleteQueue: Вы уверены в том, что хотите удалить очередь %{queue}?
|
29
30
|
Queues: Очереди
|
data/web/views/scheduled.slim
CHANGED
@@ -26,5 +26,6 @@ header.row
|
|
26
26
|
td= msg['class']
|
27
27
|
td= display_args(msg['args'])
|
28
28
|
input.btn.btn-danger.pull-right type="submit" name="delete" value="#{t('Delete')}"
|
29
|
+
input.btn.btn-danger.pull-right type="submit" name="add_to_queue" value="#{t('AddToQueue')}"
|
29
30
|
- else
|
30
31
|
.alert.alert-success = t('NoScheduledFound')
|
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.
|
4
|
+
version: 2.13.0
|
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: 2013-
|
12
|
+
date: 2013-07-09 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: redis
|
@@ -203,7 +203,7 @@ dependencies:
|
|
203
203
|
- - ! '>='
|
204
204
|
- !ruby/object:Gem::Version
|
205
205
|
version: '0'
|
206
|
-
description: Simple, efficient
|
206
|
+
description: Simple, efficient background processing for Ruby
|
207
207
|
email:
|
208
208
|
- mperham@gmail.com
|
209
209
|
executables:
|
@@ -278,6 +278,7 @@ files:
|
|
278
278
|
- test/test_sidekiq.rb
|
279
279
|
- test/test_testing.rb
|
280
280
|
- test/test_testing_inline.rb
|
281
|
+
- test/test_util.rb
|
281
282
|
- test/test_web.rb
|
282
283
|
- web/assets/images/bootstrap/glyphicons-halflings-white.png
|
283
284
|
- web/assets/images/bootstrap/glyphicons-halflings.png
|
@@ -340,7 +341,7 @@ rubyforge_project:
|
|
340
341
|
rubygems_version: 1.8.23
|
341
342
|
signing_key:
|
342
343
|
specification_version: 3
|
343
|
-
summary: Simple, efficient
|
344
|
+
summary: Simple, efficient background processing for Ruby
|
344
345
|
test_files:
|
345
346
|
- test/config.yml
|
346
347
|
- test/env_based_config.yml
|
@@ -362,4 +363,5 @@ test_files:
|
|
362
363
|
- test/test_sidekiq.rb
|
363
364
|
- test/test_testing.rb
|
364
365
|
- test/test_testing_inline.rb
|
366
|
+
- test/test_util.rb
|
365
367
|
- test/test_web.rb
|