sidekiq 4.2.9 → 4.2.10
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/.github/issue_template.md +6 -1
- data/.travis.yml +10 -5
- data/Changes.md +9 -0
- data/Ent-Changes.md +9 -0
- data/Pro-Changes.md +29 -0
- data/bin/sidekiqload +11 -11
- data/lib/sidekiq.rb +1 -1
- data/lib/sidekiq/api.rb +20 -12
- data/lib/sidekiq/middleware/server/logging.rb +8 -17
- data/lib/sidekiq/processor.rb +16 -7
- data/lib/sidekiq/testing.rb +6 -0
- data/lib/sidekiq/version.rb +1 -1
- data/lib/sidekiq/web/application.rb +2 -2
- data/lib/sidekiq/web/helpers.rb +2 -1
- data/sidekiq.gemspec +8 -2
- data/web/assets/javascripts/dashboard.js +1 -1
- data/web/locales/fa.yml +79 -0
- data/web/views/_job_info.erb +1 -1
- data/web/views/dashboard.erb +2 -2
- data/web/views/morgue.erb +2 -0
- data/web/views/queue.erb +2 -2
- data/web/views/queues.erb +2 -2
- data/web/views/retry.erb +1 -1
- metadata +74 -63
- data/test/config.yml +0 -9
- data/test/env_based_config.yml +0 -11
- data/test/fake_env.rb +0 -1
- data/test/fixtures/en.yml +0 -2
- data/test/helper.rb +0 -75
- data/test/test_actors.rb +0 -138
- data/test/test_api.rb +0 -528
- data/test/test_cli.rb +0 -418
- data/test/test_client.rb +0 -266
- data/test/test_exception_handler.rb +0 -56
- data/test/test_extensions.rb +0 -129
- data/test/test_fetch.rb +0 -50
- data/test/test_launcher.rb +0 -92
- data/test/test_logging.rb +0 -35
- data/test/test_manager.rb +0 -50
- data/test/test_middleware.rb +0 -158
- data/test/test_processor.rb +0 -249
- data/test/test_rails.rb +0 -22
- data/test/test_redis_connection.rb +0 -132
- data/test/test_retry.rb +0 -326
- data/test/test_retry_exhausted.rb +0 -149
- data/test/test_scheduled.rb +0 -115
- data/test/test_scheduling.rb +0 -58
- data/test/test_sidekiq.rb +0 -107
- data/test/test_testing.rb +0 -143
- data/test/test_testing_fake.rb +0 -359
- data/test/test_testing_inline.rb +0 -94
- data/test/test_util.rb +0 -13
- data/test/test_web.rb +0 -679
- data/test/test_web_helpers.rb +0 -54
data/test/test_processor.rb
DELETED
@@ -1,249 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
require_relative 'helper'
|
3
|
-
require 'sidekiq/fetch'
|
4
|
-
require 'sidekiq/cli'
|
5
|
-
require 'sidekiq/processor'
|
6
|
-
|
7
|
-
class TestProcessor < Sidekiq::Test
|
8
|
-
TestException = Class.new(StandardError)
|
9
|
-
TEST_EXCEPTION = TestException.new("kerboom!")
|
10
|
-
|
11
|
-
describe 'processor' do
|
12
|
-
before do
|
13
|
-
$invokes = 0
|
14
|
-
@mgr = Minitest::Mock.new
|
15
|
-
@mgr.expect(:options, {:queues => ['default']})
|
16
|
-
@mgr.expect(:options, {:queues => ['default']})
|
17
|
-
@processor = ::Sidekiq::Processor.new(@mgr)
|
18
|
-
end
|
19
|
-
|
20
|
-
class MockWorker
|
21
|
-
include Sidekiq::Worker
|
22
|
-
def perform(args)
|
23
|
-
raise TEST_EXCEPTION if args == 'boom'
|
24
|
-
args.pop if args.is_a? Array
|
25
|
-
$invokes += 1
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
def work(msg, queue='queue:default')
|
30
|
-
Sidekiq::BasicFetch::UnitOfWork.new(queue, msg)
|
31
|
-
end
|
32
|
-
|
33
|
-
it 'processes as expected' do
|
34
|
-
msg = Sidekiq.dump_json({ 'class' => MockWorker.to_s, 'args' => ['myarg'] })
|
35
|
-
@processor.process(work(msg))
|
36
|
-
assert_equal 1, $invokes
|
37
|
-
end
|
38
|
-
|
39
|
-
it 'executes a worker as expected' do
|
40
|
-
worker = Minitest::Mock.new
|
41
|
-
worker.expect(:perform, nil, [1, 2, 3])
|
42
|
-
@processor.execute_job(worker, [1, 2, 3])
|
43
|
-
end
|
44
|
-
|
45
|
-
it 're-raises exceptions after handling' do
|
46
|
-
msg = Sidekiq.dump_json({ 'class' => MockWorker.to_s, 'args' => ['boom'] })
|
47
|
-
re_raise = false
|
48
|
-
|
49
|
-
begin
|
50
|
-
@processor.process(work(msg))
|
51
|
-
flunk "Expected exception"
|
52
|
-
rescue TestException
|
53
|
-
re_raise = true
|
54
|
-
end
|
55
|
-
|
56
|
-
assert_equal 0, $invokes
|
57
|
-
assert re_raise, "does not re-raise exceptions after handling"
|
58
|
-
end
|
59
|
-
|
60
|
-
it 'does not modify original arguments' do
|
61
|
-
msg = { 'class' => MockWorker.to_s, 'args' => [['myarg']] }
|
62
|
-
msgstr = Sidekiq.dump_json(msg)
|
63
|
-
@mgr.expect(:processor_done, nil, [@processor])
|
64
|
-
@processor.process(work(msgstr))
|
65
|
-
assert_equal [['myarg']], msg['args']
|
66
|
-
end
|
67
|
-
|
68
|
-
describe 'exception handling' do
|
69
|
-
let(:errors) { [] }
|
70
|
-
let(:error_handler) do
|
71
|
-
proc do |exception, context|
|
72
|
-
errors << { exception: exception, context: context }
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
before do
|
77
|
-
Sidekiq.error_handlers << error_handler
|
78
|
-
end
|
79
|
-
|
80
|
-
after do
|
81
|
-
Sidekiq.error_handlers.pop
|
82
|
-
end
|
83
|
-
|
84
|
-
it 'handles exceptions raised by the job' do
|
85
|
-
job_hash = { 'class' => MockWorker.to_s, 'args' => ['boom'] }
|
86
|
-
msg = Sidekiq.dump_json(job_hash)
|
87
|
-
job = work(msg)
|
88
|
-
begin
|
89
|
-
@processor.instance_variable_set(:'@job', job)
|
90
|
-
@processor.process(job)
|
91
|
-
rescue TestException
|
92
|
-
end
|
93
|
-
assert_equal 1, errors.count
|
94
|
-
assert_instance_of TestException, errors.first[:exception]
|
95
|
-
assert_equal msg, errors.first[:context][:jobstr]
|
96
|
-
assert_equal job_hash, errors.first[:context][:job]
|
97
|
-
end
|
98
|
-
|
99
|
-
it 'handles exceptions raised by the reloader' do
|
100
|
-
job_hash = { 'class' => MockWorker.to_s, 'args' => ['boom'] }
|
101
|
-
msg = Sidekiq.dump_json(job_hash)
|
102
|
-
@processor.instance_variable_set(:'@reloader', proc { raise TEST_EXCEPTION })
|
103
|
-
job = work(msg)
|
104
|
-
begin
|
105
|
-
@processor.instance_variable_set(:'@job', job)
|
106
|
-
@processor.process(job)
|
107
|
-
rescue TestException
|
108
|
-
end
|
109
|
-
assert_equal 1, errors.count
|
110
|
-
assert_instance_of TestException, errors.first[:exception]
|
111
|
-
assert_equal msg, errors.first[:context][:jobstr]
|
112
|
-
assert_equal job_hash, errors.first[:context][:job]
|
113
|
-
end
|
114
|
-
end
|
115
|
-
|
116
|
-
describe 'acknowledgement' do
|
117
|
-
class ExceptionRaisingMiddleware
|
118
|
-
def initialize(raise_before_yield, raise_after_yield, skip)
|
119
|
-
@raise_before_yield = raise_before_yield
|
120
|
-
@raise_after_yield = raise_after_yield
|
121
|
-
@skip = skip
|
122
|
-
end
|
123
|
-
|
124
|
-
def call(worker, item, queue)
|
125
|
-
raise TEST_EXCEPTION if @raise_before_yield
|
126
|
-
yield unless @skip
|
127
|
-
raise TEST_EXCEPTION if @raise_after_yield
|
128
|
-
end
|
129
|
-
end
|
130
|
-
|
131
|
-
let(:raise_before_yield) { false }
|
132
|
-
let(:raise_after_yield) { false }
|
133
|
-
let(:skip_job) { false }
|
134
|
-
let(:worker_args) { ['myarg'] }
|
135
|
-
let(:work) { MiniTest::Mock.new }
|
136
|
-
|
137
|
-
before do
|
138
|
-
work.expect(:queue_name, 'queue:default')
|
139
|
-
work.expect(:job, Sidekiq.dump_json({ 'class' => MockWorker.to_s, 'args' => worker_args }))
|
140
|
-
Sidekiq.server_middleware do |chain|
|
141
|
-
chain.prepend ExceptionRaisingMiddleware, raise_before_yield, raise_after_yield, skip_job
|
142
|
-
end
|
143
|
-
end
|
144
|
-
|
145
|
-
after do
|
146
|
-
Sidekiq.server_middleware do |chain|
|
147
|
-
chain.remove ExceptionRaisingMiddleware
|
148
|
-
end
|
149
|
-
work.verify
|
150
|
-
end
|
151
|
-
|
152
|
-
describe 'middleware throws an exception before processing the work' do
|
153
|
-
let(:raise_before_yield) { true }
|
154
|
-
|
155
|
-
it 'does not ack' do
|
156
|
-
begin
|
157
|
-
@processor.process(work)
|
158
|
-
flunk "Expected #process to raise exception"
|
159
|
-
rescue TestException
|
160
|
-
end
|
161
|
-
end
|
162
|
-
end
|
163
|
-
|
164
|
-
describe 'middleware throws an exception after processing the work' do
|
165
|
-
let(:raise_after_yield) { true }
|
166
|
-
|
167
|
-
it 'acks the job' do
|
168
|
-
work.expect(:acknowledge, nil)
|
169
|
-
begin
|
170
|
-
@processor.process(work)
|
171
|
-
flunk "Expected #process to raise exception"
|
172
|
-
rescue TestException
|
173
|
-
end
|
174
|
-
end
|
175
|
-
end
|
176
|
-
|
177
|
-
describe 'middleware decides to skip work' do
|
178
|
-
let(:skip_job) { true }
|
179
|
-
|
180
|
-
it 'acks the job' do
|
181
|
-
work.expect(:acknowledge, nil)
|
182
|
-
@mgr.expect(:processor_done, nil, [@processor])
|
183
|
-
@processor.process(work)
|
184
|
-
end
|
185
|
-
end
|
186
|
-
|
187
|
-
describe 'worker raises an exception' do
|
188
|
-
let(:worker_args) { ['boom'] }
|
189
|
-
|
190
|
-
it 'acks the job' do
|
191
|
-
work.expect(:acknowledge, nil)
|
192
|
-
begin
|
193
|
-
@processor.process(work)
|
194
|
-
flunk "Expected #process to raise exception"
|
195
|
-
rescue TestException
|
196
|
-
end
|
197
|
-
end
|
198
|
-
end
|
199
|
-
|
200
|
-
describe 'everything goes well' do
|
201
|
-
it 'acks the job' do
|
202
|
-
work.expect(:acknowledge, nil)
|
203
|
-
@mgr.expect(:processor_done, nil, [@processor])
|
204
|
-
@processor.process(work)
|
205
|
-
end
|
206
|
-
end
|
207
|
-
end
|
208
|
-
|
209
|
-
describe 'stats' do
|
210
|
-
before do
|
211
|
-
Sidekiq.redis {|c| c.flushdb }
|
212
|
-
end
|
213
|
-
|
214
|
-
describe 'when successful' do
|
215
|
-
let(:processed_today_key) { "stat:processed:#{Time.now.utc.strftime("%Y-%m-%d")}" }
|
216
|
-
|
217
|
-
def successful_job
|
218
|
-
msg = Sidekiq.dump_json({ 'class' => MockWorker.to_s, 'args' => ['myarg'] })
|
219
|
-
@mgr.expect(:processor_done, nil, [@processor])
|
220
|
-
@processor.process(work(msg))
|
221
|
-
end
|
222
|
-
|
223
|
-
it 'increments processed stat' do
|
224
|
-
Sidekiq::Processor::PROCESSED.value = 0
|
225
|
-
successful_job
|
226
|
-
assert_equal 1, Sidekiq::Processor::PROCESSED.value
|
227
|
-
end
|
228
|
-
end
|
229
|
-
|
230
|
-
describe 'when failed' do
|
231
|
-
let(:failed_today_key) { "stat:failed:#{Time.now.utc.strftime("%Y-%m-%d")}" }
|
232
|
-
|
233
|
-
def failed_job
|
234
|
-
msg = Sidekiq.dump_json({ 'class' => MockWorker.to_s, 'args' => ['boom'] })
|
235
|
-
begin
|
236
|
-
@processor.process(work(msg))
|
237
|
-
rescue TestException
|
238
|
-
end
|
239
|
-
end
|
240
|
-
|
241
|
-
it 'increments failed stat' do
|
242
|
-
Sidekiq::Processor::FAILURE.value = 0
|
243
|
-
failed_job
|
244
|
-
assert_equal 1, Sidekiq::Processor::FAILURE.value
|
245
|
-
end
|
246
|
-
end
|
247
|
-
end
|
248
|
-
end
|
249
|
-
end
|
data/test/test_rails.rb
DELETED
@@ -1,22 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
require_relative 'helper'
|
3
|
-
|
4
|
-
$HAS_AJ = true
|
5
|
-
begin
|
6
|
-
require 'active_job'
|
7
|
-
rescue LoadError
|
8
|
-
$HAS_AJ = false
|
9
|
-
end
|
10
|
-
|
11
|
-
class TestRails < Sidekiq::Test
|
12
|
-
|
13
|
-
describe 'ActiveJob' do
|
14
|
-
it 'does not allow Sidekiq::Worker in AJ::Base classes' do
|
15
|
-
ex = assert_raises ArgumentError do
|
16
|
-
c = Class.new(ActiveJob::Base)
|
17
|
-
c.send(:include, Sidekiq::Worker)
|
18
|
-
end
|
19
|
-
assert_includes ex.message, "cannot include"
|
20
|
-
end if $HAS_AJ
|
21
|
-
end
|
22
|
-
end
|
@@ -1,132 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
require_relative 'helper'
|
3
|
-
|
4
|
-
class TestRedisConnection < Sidekiq::Test
|
5
|
-
|
6
|
-
describe ".create" do
|
7
|
-
|
8
|
-
it "creates a pooled redis connection" do
|
9
|
-
pool = Sidekiq::RedisConnection.create
|
10
|
-
assert_equal Redis, pool.checkout.class
|
11
|
-
end
|
12
|
-
|
13
|
-
describe "network_timeout" do
|
14
|
-
it "sets a custom network_timeout if specified" do
|
15
|
-
pool = Sidekiq::RedisConnection.create(:network_timeout => 8)
|
16
|
-
redis = pool.checkout
|
17
|
-
|
18
|
-
assert_equal 8, redis.client.timeout
|
19
|
-
end
|
20
|
-
|
21
|
-
it "uses the default network_timeout if none specified" do
|
22
|
-
pool = Sidekiq::RedisConnection.create
|
23
|
-
redis = pool.checkout
|
24
|
-
|
25
|
-
assert_equal 5, redis.client.timeout
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
describe "namespace" do
|
30
|
-
it "uses a given :namespace set by a symbol key" do
|
31
|
-
pool = Sidekiq::RedisConnection.create(:namespace => "xxx")
|
32
|
-
assert_equal "xxx", pool.checkout.namespace
|
33
|
-
end
|
34
|
-
|
35
|
-
it "uses a given :namespace set by a string key" do
|
36
|
-
pool = Sidekiq::RedisConnection.create("namespace" => "xxx")
|
37
|
-
assert_equal "xxx", pool.checkout.namespace
|
38
|
-
end
|
39
|
-
|
40
|
-
it "uses given :namespace over :namespace from Sidekiq.options" do
|
41
|
-
Sidekiq.options[:namespace] = "xxx"
|
42
|
-
pool = Sidekiq::RedisConnection.create(:namespace => "yyy")
|
43
|
-
assert_equal "yyy", pool.checkout.namespace
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
describe "socket path" do
|
48
|
-
it "uses a given :path" do
|
49
|
-
pool = Sidekiq::RedisConnection.create(:path => "/var/run/redis.sock")
|
50
|
-
assert_equal "unix", pool.checkout.client.scheme
|
51
|
-
assert_equal "redis:///var/run/redis.sock/0", pool.checkout.client.id
|
52
|
-
end
|
53
|
-
|
54
|
-
it "uses a given :path and :db" do
|
55
|
-
pool = Sidekiq::RedisConnection.create(:path => "/var/run/redis.sock", :db => 8)
|
56
|
-
assert_equal "unix", pool.checkout.client.scheme
|
57
|
-
assert_equal "redis:///var/run/redis.sock/8", pool.checkout.client.id
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
describe "pool_timeout" do
|
62
|
-
it "uses a given :timeout over the default of 1" do
|
63
|
-
pool = Sidekiq::RedisConnection.create(:pool_timeout => 5)
|
64
|
-
|
65
|
-
assert_equal 5, pool.instance_eval{ @timeout }
|
66
|
-
end
|
67
|
-
|
68
|
-
it "uses the default timeout of 1 if no override" do
|
69
|
-
pool = Sidekiq::RedisConnection.create
|
70
|
-
|
71
|
-
assert_equal 1, pool.instance_eval{ @timeout }
|
72
|
-
end
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
describe ".determine_redis_provider" do
|
77
|
-
|
78
|
-
before do
|
79
|
-
@old_env = ENV.to_hash
|
80
|
-
end
|
81
|
-
|
82
|
-
after do
|
83
|
-
ENV.update(@old_env)
|
84
|
-
end
|
85
|
-
|
86
|
-
def with_env_var(var, uri, skip_provider=false)
|
87
|
-
vars = ['REDISTOGO_URL', 'REDIS_PROVIDER', 'REDIS_URL'] - [var]
|
88
|
-
vars.each do |v|
|
89
|
-
next if skip_provider
|
90
|
-
ENV[v] = nil
|
91
|
-
end
|
92
|
-
ENV[var] = uri
|
93
|
-
assert_equal uri, Sidekiq::RedisConnection.__send__(:determine_redis_provider)
|
94
|
-
ENV[var] = nil
|
95
|
-
end
|
96
|
-
|
97
|
-
describe "with REDISTOGO_URL and a parallel REDIS_PROVIDER set" do
|
98
|
-
it "sets connection URI to the provider" do
|
99
|
-
uri = 'redis://sidekiq-redis-provider:6379/0'
|
100
|
-
provider = 'SIDEKIQ_REDIS_PROVIDER'
|
101
|
-
|
102
|
-
ENV['REDIS_PROVIDER'] = provider
|
103
|
-
ENV[provider] = uri
|
104
|
-
ENV['REDISTOGO_URL'] = 'redis://redis-to-go:6379/0'
|
105
|
-
with_env_var provider, uri, true
|
106
|
-
|
107
|
-
ENV[provider] = nil
|
108
|
-
end
|
109
|
-
end
|
110
|
-
|
111
|
-
describe "with REDIS_PROVIDER set" do
|
112
|
-
it "sets connection URI to the provider" do
|
113
|
-
uri = 'redis://sidekiq-redis-provider:6379/0'
|
114
|
-
provider = 'SIDEKIQ_REDIS_PROVIDER'
|
115
|
-
|
116
|
-
ENV['REDIS_PROVIDER'] = provider
|
117
|
-
ENV[provider] = uri
|
118
|
-
|
119
|
-
with_env_var provider, uri, true
|
120
|
-
|
121
|
-
ENV[provider] = nil
|
122
|
-
end
|
123
|
-
end
|
124
|
-
|
125
|
-
describe "with REDIS_URL set" do
|
126
|
-
it "sets connection URI to custom uri" do
|
127
|
-
with_env_var 'REDIS_URL', 'redis://redis-uri:6379/0'
|
128
|
-
end
|
129
|
-
end
|
130
|
-
|
131
|
-
end
|
132
|
-
end
|
data/test/test_retry.rb
DELETED
@@ -1,326 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
# frozen_string_literal: true
|
3
|
-
require_relative 'helper'
|
4
|
-
require 'sidekiq/scheduled'
|
5
|
-
require 'sidekiq/middleware/server/retry_jobs'
|
6
|
-
|
7
|
-
class TestRetry < Sidekiq::Test
|
8
|
-
describe 'middleware' do
|
9
|
-
class SomeWorker
|
10
|
-
include Sidekiq::Worker
|
11
|
-
end
|
12
|
-
|
13
|
-
before do
|
14
|
-
Sidekiq.redis {|c| c.flushdb }
|
15
|
-
end
|
16
|
-
|
17
|
-
def worker
|
18
|
-
@worker ||= SomeWorker.new
|
19
|
-
end
|
20
|
-
|
21
|
-
def handler(options={})
|
22
|
-
@handler ||= Sidekiq::Middleware::Server::RetryJobs.new(options)
|
23
|
-
end
|
24
|
-
|
25
|
-
def job(options={})
|
26
|
-
@job ||= { 'class' => 'Bob', 'args' => [1,2,'foo'], 'retry' => true }.merge(options)
|
27
|
-
end
|
28
|
-
|
29
|
-
it 'allows disabling retry' do
|
30
|
-
assert_raises RuntimeError do
|
31
|
-
handler.call(worker, job('retry' => false), 'default') do
|
32
|
-
raise "kerblammo!"
|
33
|
-
end
|
34
|
-
end
|
35
|
-
assert_equal 0, Sidekiq::RetrySet.new.size
|
36
|
-
end
|
37
|
-
|
38
|
-
it 'allows a numeric retry' do
|
39
|
-
assert_raises RuntimeError do
|
40
|
-
handler.call(worker, job('retry' => 2), 'default') do
|
41
|
-
raise "kerblammo!"
|
42
|
-
end
|
43
|
-
end
|
44
|
-
assert_equal 1, Sidekiq::RetrySet.new.size
|
45
|
-
assert_equal 0, Sidekiq::DeadSet.new.size
|
46
|
-
end
|
47
|
-
|
48
|
-
it 'allows 0 retry => no retry and dead queue' do
|
49
|
-
assert_raises RuntimeError do
|
50
|
-
handler.call(worker, job('retry' => 0), 'default') do
|
51
|
-
raise "kerblammo!"
|
52
|
-
end
|
53
|
-
end
|
54
|
-
assert_equal 0, Sidekiq::RetrySet.new.size
|
55
|
-
assert_equal 1, Sidekiq::DeadSet.new.size
|
56
|
-
end
|
57
|
-
|
58
|
-
it 'handles zany characters in error message, #1705' do
|
59
|
-
skip 'skipped! test requires ruby 2.1+' if RUBY_VERSION <= '2.1.0'
|
60
|
-
|
61
|
-
assert_raises RuntimeError do
|
62
|
-
handler.call(worker, job, 'default') do
|
63
|
-
raise "kerblammo! #{195.chr}"
|
64
|
-
end
|
65
|
-
end
|
66
|
-
assert_equal "kerblammo! �", job["error_message"]
|
67
|
-
end
|
68
|
-
|
69
|
-
|
70
|
-
it 'allows a max_retries option in initializer' do
|
71
|
-
max_retries = 7
|
72
|
-
1.upto(max_retries + 1) do
|
73
|
-
assert_raises RuntimeError do
|
74
|
-
handler(:max_retries => max_retries).call(worker, job, 'default') do
|
75
|
-
raise "kerblammo!"
|
76
|
-
end
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
assert_equal max_retries, Sidekiq::RetrySet.new.size
|
81
|
-
assert_equal 1, Sidekiq::DeadSet.new.size
|
82
|
-
end
|
83
|
-
|
84
|
-
it 'saves backtraces' do
|
85
|
-
c = nil
|
86
|
-
assert_raises RuntimeError do
|
87
|
-
handler.call(worker, job('backtrace' => true), 'default') do
|
88
|
-
c = caller(0); raise "kerblammo!"
|
89
|
-
end
|
90
|
-
end
|
91
|
-
assert job["error_backtrace"]
|
92
|
-
assert_equal c[0], job["error_backtrace"][0]
|
93
|
-
end
|
94
|
-
|
95
|
-
it 'saves partial backtraces' do
|
96
|
-
c = nil
|
97
|
-
assert_raises RuntimeError do
|
98
|
-
handler.call(worker, job('backtrace' => 3), 'default') do
|
99
|
-
c = caller(0)[0...3]; raise "kerblammo!"
|
100
|
-
end
|
101
|
-
end
|
102
|
-
assert job["error_backtrace"]
|
103
|
-
assert_equal c, job["error_backtrace"]
|
104
|
-
assert_equal 3, c.size
|
105
|
-
end
|
106
|
-
|
107
|
-
it 'handles a new failed message' do
|
108
|
-
assert_raises RuntimeError do
|
109
|
-
handler.call(worker, job, 'default') do
|
110
|
-
raise "kerblammo!"
|
111
|
-
end
|
112
|
-
end
|
113
|
-
assert_equal 'default', job["queue"]
|
114
|
-
assert_equal 'kerblammo!', job["error_message"]
|
115
|
-
assert_equal 'RuntimeError', job["error_class"]
|
116
|
-
assert_equal 0, job["retry_count"]
|
117
|
-
refute job["error_backtrace"]
|
118
|
-
assert job["failed_at"]
|
119
|
-
end
|
120
|
-
|
121
|
-
it 'shuts down without retrying work-in-progress, which will resume' do
|
122
|
-
rs = Sidekiq::RetrySet.new
|
123
|
-
assert_equal 0, rs.size
|
124
|
-
msg = { 'class' => 'Bob', 'args' => [1,2,'foo'], 'retry' => true }
|
125
|
-
assert_raises Sidekiq::Shutdown do
|
126
|
-
handler.call(worker, msg, 'default') do
|
127
|
-
raise Sidekiq::Shutdown
|
128
|
-
end
|
129
|
-
end
|
130
|
-
assert_equal 0, rs.size
|
131
|
-
end
|
132
|
-
|
133
|
-
it 'shuts down cleanly when shutdown causes exception' do
|
134
|
-
skip('Not supported in Ruby < 2.1.0') if RUBY_VERSION < '2.1.0'
|
135
|
-
|
136
|
-
rs = Sidekiq::RetrySet.new
|
137
|
-
assert_equal 0, rs.size
|
138
|
-
msg = { 'class' => 'Bob', 'args' => [1,2,'foo'], 'retry' => true }
|
139
|
-
assert_raises Sidekiq::Shutdown do
|
140
|
-
handler.call(worker, msg, 'default') do
|
141
|
-
begin
|
142
|
-
raise Sidekiq::Shutdown
|
143
|
-
rescue Interrupt
|
144
|
-
raise "kerblammo!"
|
145
|
-
end
|
146
|
-
end
|
147
|
-
end
|
148
|
-
assert_equal 0, rs.size
|
149
|
-
end
|
150
|
-
|
151
|
-
it 'shuts down cleanly when shutdown causes chained exceptions' do
|
152
|
-
skip('Not supported in Ruby < 2.1.0') if RUBY_VERSION < '2.1.0'
|
153
|
-
|
154
|
-
rs = Sidekiq::RetrySet.new
|
155
|
-
assert_equal 0, rs.size
|
156
|
-
assert_raises Sidekiq::Shutdown do
|
157
|
-
handler.call(worker, job, 'default') do
|
158
|
-
begin
|
159
|
-
raise Sidekiq::Shutdown
|
160
|
-
rescue Interrupt
|
161
|
-
begin
|
162
|
-
raise "kerblammo!"
|
163
|
-
rescue
|
164
|
-
raise "kablooie!"
|
165
|
-
end
|
166
|
-
end
|
167
|
-
end
|
168
|
-
end
|
169
|
-
assert_equal 0, rs.size
|
170
|
-
end
|
171
|
-
|
172
|
-
it 'allows a retry queue' do
|
173
|
-
assert_raises RuntimeError do
|
174
|
-
handler.call(worker, job("retry_queue" => 'retryx'), 'default') do
|
175
|
-
raise "kerblammo!"
|
176
|
-
end
|
177
|
-
end
|
178
|
-
assert_equal 'retryx', job["queue"]
|
179
|
-
assert_equal 'kerblammo!', job["error_message"]
|
180
|
-
assert_equal 'RuntimeError', job["error_class"]
|
181
|
-
assert_equal 0, job["retry_count"]
|
182
|
-
refute job["error_backtrace"]
|
183
|
-
assert job["failed_at"]
|
184
|
-
end
|
185
|
-
|
186
|
-
it 'handles a recurring failed message' do
|
187
|
-
now = Time.now.to_f
|
188
|
-
msg = {"queue"=>"default", "error_message"=>"kerblammo!", "error_class"=>"RuntimeError", "failed_at"=>now, "retry_count"=>10}
|
189
|
-
assert_raises RuntimeError do
|
190
|
-
handler.call(worker, job(msg), 'default') do
|
191
|
-
raise "kerblammo!"
|
192
|
-
end
|
193
|
-
end
|
194
|
-
assert_equal 'default', job["queue"]
|
195
|
-
assert_equal 'kerblammo!', job["error_message"]
|
196
|
-
assert_equal 'RuntimeError', job["error_class"]
|
197
|
-
assert_equal 11, job["retry_count"]
|
198
|
-
assert job["failed_at"]
|
199
|
-
end
|
200
|
-
|
201
|
-
it 'throws away old messages after too many retries (using the default)' do
|
202
|
-
q = Sidekiq::Queue.new
|
203
|
-
rs = Sidekiq::RetrySet.new
|
204
|
-
ds = Sidekiq::DeadSet.new
|
205
|
-
assert_equal 0, q.size
|
206
|
-
assert_equal 0, rs.size
|
207
|
-
assert_equal 0, ds.size
|
208
|
-
now = Time.now.to_f
|
209
|
-
msg = {"queue"=>"default", "error_message"=>"kerblammo!", "error_class"=>"RuntimeError", "failed_at"=>now, "retry_count"=>25}
|
210
|
-
assert_raises RuntimeError do
|
211
|
-
handler.call(worker, job(msg), 'default') do
|
212
|
-
raise "kerblammo!"
|
213
|
-
end
|
214
|
-
end
|
215
|
-
assert_equal 0, q.size
|
216
|
-
assert_equal 0, rs.size
|
217
|
-
assert_equal 1, ds.size
|
218
|
-
end
|
219
|
-
|
220
|
-
describe "custom retry delay" do
|
221
|
-
before do
|
222
|
-
@old_logger = Sidekiq.logger
|
223
|
-
@tmp_log_path = '/tmp/sidekiq-retries.log'
|
224
|
-
Sidekiq.logger = Logger.new(@tmp_log_path)
|
225
|
-
end
|
226
|
-
|
227
|
-
after do
|
228
|
-
Sidekiq.logger = @old_logger
|
229
|
-
Sidekiq.options.delete(:logfile)
|
230
|
-
File.unlink @tmp_log_path if File.exist?(@tmp_log_path)
|
231
|
-
end
|
232
|
-
|
233
|
-
class CustomWorkerWithoutException
|
234
|
-
include Sidekiq::Worker
|
235
|
-
|
236
|
-
sidekiq_retry_in do |count|
|
237
|
-
count * 2
|
238
|
-
end
|
239
|
-
end
|
240
|
-
|
241
|
-
class CustomWorkerWithException
|
242
|
-
include Sidekiq::Worker
|
243
|
-
|
244
|
-
sidekiq_retry_in do |count, exception|
|
245
|
-
case exception
|
246
|
-
when ArgumentError
|
247
|
-
count * 4
|
248
|
-
else
|
249
|
-
count * 2
|
250
|
-
end
|
251
|
-
end
|
252
|
-
end
|
253
|
-
|
254
|
-
class ErrorWorker
|
255
|
-
include Sidekiq::Worker
|
256
|
-
|
257
|
-
sidekiq_retry_in do |count|
|
258
|
-
count / 0
|
259
|
-
end
|
260
|
-
end
|
261
|
-
|
262
|
-
it "retries with a default delay" do
|
263
|
-
refute_equal 4, handler.__send__(:delay_for, worker, 2, StandardError.new)
|
264
|
-
end
|
265
|
-
|
266
|
-
it "retries with a custom delay and exception 1" do
|
267
|
-
assert_equal 8, handler.__send__(:delay_for, CustomWorkerWithException, 2, ArgumentError.new)
|
268
|
-
end
|
269
|
-
|
270
|
-
it "retries with a custom delay and exception 2" do
|
271
|
-
assert_equal 4, handler.__send__(:delay_for, CustomWorkerWithException, 2, StandardError.new)
|
272
|
-
end
|
273
|
-
|
274
|
-
it "retries with a custom delay without exception" do
|
275
|
-
assert_equal 4, handler.__send__(:delay_for, CustomWorkerWithoutException, 2, StandardError.new)
|
276
|
-
end
|
277
|
-
|
278
|
-
it "falls back to the default retry on exception" do
|
279
|
-
refute_equal 4, handler.__send__(:delay_for, ErrorWorker, 2, StandardError.new)
|
280
|
-
assert_match(/Failure scheduling retry using the defined `sidekiq_retry_in`/,
|
281
|
-
File.read(@tmp_log_path), 'Log entry missing for sidekiq_retry_in')
|
282
|
-
end
|
283
|
-
end
|
284
|
-
|
285
|
-
describe 'handles errors withouth cause' do
|
286
|
-
before do
|
287
|
-
@error = nil
|
288
|
-
begin
|
289
|
-
raise ::StandardError, 'Error'
|
290
|
-
rescue ::StandardError => e
|
291
|
-
@error = e
|
292
|
-
end
|
293
|
-
end
|
294
|
-
|
295
|
-
it "does not recurse infinitely checking if it's a shutdown" do
|
296
|
-
assert(!Sidekiq::Middleware::Server::RetryJobs.new.send(
|
297
|
-
:exception_caused_by_shutdown?, @error))
|
298
|
-
end
|
299
|
-
end
|
300
|
-
|
301
|
-
describe 'handles errors with circular causes' do
|
302
|
-
before do
|
303
|
-
@error = nil
|
304
|
-
begin
|
305
|
-
begin
|
306
|
-
raise ::StandardError, 'Error 1'
|
307
|
-
rescue ::StandardError => e1
|
308
|
-
begin
|
309
|
-
raise ::StandardError, 'Error 2'
|
310
|
-
rescue ::StandardError
|
311
|
-
raise e1
|
312
|
-
end
|
313
|
-
end
|
314
|
-
rescue ::StandardError => e
|
315
|
-
@error = e
|
316
|
-
end
|
317
|
-
end
|
318
|
-
|
319
|
-
it "does not recurse infinitely checking if it's a shutdown" do
|
320
|
-
assert(!Sidekiq::Middleware::Server::RetryJobs.new.send(
|
321
|
-
:exception_caused_by_shutdown?, @error))
|
322
|
-
end
|
323
|
-
end
|
324
|
-
end
|
325
|
-
|
326
|
-
end
|