sidekiq 2.15.1 → 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 +7 -0
- data/.github/contributing.md +32 -0
- data/.github/issue_template.md +9 -0
- data/.gitignore +1 -0
- data/.travis.yml +16 -17
- data/3.0-Upgrade.md +70 -0
- data/4.0-Upgrade.md +53 -0
- data/COMM-LICENSE +56 -44
- data/Changes.md +644 -1
- data/Ent-Changes.md +173 -0
- data/Gemfile +27 -0
- data/LICENSE +1 -1
- data/Pro-2.0-Upgrade.md +138 -0
- data/Pro-3.0-Upgrade.md +44 -0
- data/Pro-Changes.md +457 -3
- data/README.md +46 -29
- data/Rakefile +6 -3
- data/bin/sidekiq +4 -0
- data/bin/sidekiqctl +41 -20
- data/bin/sidekiqload +154 -0
- data/code_of_conduct.md +50 -0
- data/lib/generators/sidekiq/templates/worker.rb.erb +9 -0
- data/lib/generators/sidekiq/templates/worker_spec.rb.erb +6 -0
- data/lib/generators/sidekiq/templates/worker_test.rb.erb +8 -0
- data/lib/generators/sidekiq/worker_generator.rb +49 -0
- data/lib/sidekiq.rb +141 -29
- data/lib/sidekiq/api.rb +540 -106
- data/lib/sidekiq/cli.rb +131 -71
- data/lib/sidekiq/client.rb +168 -96
- data/lib/sidekiq/core_ext.rb +36 -8
- data/lib/sidekiq/exception_handler.rb +20 -28
- data/lib/sidekiq/extensions/action_mailer.rb +25 -5
- data/lib/sidekiq/extensions/active_record.rb +8 -4
- data/lib/sidekiq/extensions/class_methods.rb +9 -5
- data/lib/sidekiq/extensions/generic_proxy.rb +1 -0
- data/lib/sidekiq/fetch.rb +45 -101
- data/lib/sidekiq/launcher.rb +144 -30
- data/lib/sidekiq/logging.rb +69 -12
- data/lib/sidekiq/manager.rb +90 -140
- data/lib/sidekiq/middleware/chain.rb +18 -5
- data/lib/sidekiq/middleware/i18n.rb +9 -2
- data/lib/sidekiq/middleware/server/active_record.rb +1 -1
- data/lib/sidekiq/middleware/server/logging.rb +11 -11
- data/lib/sidekiq/middleware/server/retry_jobs.rb +98 -44
- data/lib/sidekiq/paginator.rb +20 -8
- data/lib/sidekiq/processor.rb +157 -96
- data/lib/sidekiq/rails.rb +109 -5
- data/lib/sidekiq/redis_connection.rb +70 -24
- data/lib/sidekiq/scheduled.rb +122 -50
- data/lib/sidekiq/testing.rb +171 -31
- data/lib/sidekiq/testing/inline.rb +1 -0
- data/lib/sidekiq/util.rb +31 -5
- data/lib/sidekiq/version.rb +2 -1
- data/lib/sidekiq/web.rb +136 -263
- data/lib/sidekiq/web/action.rb +93 -0
- data/lib/sidekiq/web/application.rb +336 -0
- data/lib/sidekiq/web/helpers.rb +278 -0
- data/lib/sidekiq/web/router.rb +100 -0
- data/lib/sidekiq/worker.rb +40 -7
- data/sidekiq.gemspec +18 -14
- data/web/assets/images/favicon.ico +0 -0
- data/web/assets/images/{status-sd8051fd480.png → status.png} +0 -0
- data/web/assets/javascripts/application.js +67 -19
- data/web/assets/javascripts/dashboard.js +138 -29
- data/web/assets/stylesheets/application.css +267 -406
- data/web/assets/stylesheets/bootstrap.css +4 -8
- data/web/locales/cs.yml +78 -0
- data/web/locales/da.yml +9 -1
- data/web/locales/de.yml +18 -9
- data/web/locales/el.yml +68 -0
- data/web/locales/en.yml +19 -4
- data/web/locales/es.yml +10 -1
- data/web/locales/fa.yml +79 -0
- data/web/locales/fr.yml +50 -32
- data/web/locales/hi.yml +75 -0
- data/web/locales/it.yml +27 -18
- data/web/locales/ja.yml +27 -12
- data/web/locales/ko.yml +8 -3
- data/web/locales/{no.yml → nb.yml} +19 -5
- data/web/locales/nl.yml +8 -3
- data/web/locales/pl.yml +0 -1
- data/web/locales/pt-br.yml +11 -4
- data/web/locales/pt.yml +8 -1
- data/web/locales/ru.yml +39 -21
- data/web/locales/sv.yml +68 -0
- data/web/locales/ta.yml +75 -0
- data/web/locales/uk.yml +76 -0
- data/web/locales/zh-cn.yml +68 -0
- data/web/locales/zh-tw.yml +68 -0
- data/web/views/_footer.erb +17 -0
- data/web/views/_job_info.erb +72 -60
- data/web/views/_nav.erb +58 -25
- data/web/views/_paging.erb +5 -5
- data/web/views/_poll_link.erb +7 -0
- data/web/views/_summary.erb +20 -14
- data/web/views/busy.erb +94 -0
- data/web/views/dashboard.erb +34 -21
- data/web/views/dead.erb +34 -0
- data/web/views/layout.erb +8 -30
- data/web/views/morgue.erb +75 -0
- data/web/views/queue.erb +37 -30
- data/web/views/queues.erb +26 -20
- data/web/views/retries.erb +60 -47
- data/web/views/retry.erb +23 -19
- data/web/views/scheduled.erb +39 -35
- data/web/views/scheduled_job_info.erb +2 -1
- metadata +152 -195
- data/Contributing.md +0 -29
- data/config.ru +0 -18
- data/lib/sidekiq/actor.rb +0 -7
- data/lib/sidekiq/capistrano.rb +0 -54
- data/lib/sidekiq/yaml_patch.rb +0 -21
- data/test/config.yml +0 -11
- data/test/env_based_config.yml +0 -11
- data/test/fake_env.rb +0 -0
- data/test/helper.rb +0 -42
- data/test/test_api.rb +0 -341
- data/test/test_cli.rb +0 -326
- data/test/test_client.rb +0 -211
- data/test/test_exception_handler.rb +0 -124
- data/test/test_extensions.rb +0 -105
- data/test/test_fetch.rb +0 -44
- data/test/test_manager.rb +0 -83
- data/test/test_middleware.rb +0 -135
- data/test/test_processor.rb +0 -160
- data/test/test_redis_connection.rb +0 -97
- data/test/test_retry.rb +0 -306
- data/test/test_scheduled.rb +0 -86
- data/test/test_scheduling.rb +0 -47
- data/test/test_sidekiq.rb +0 -37
- data/test/test_testing.rb +0 -82
- data/test/test_testing_fake.rb +0 -265
- data/test/test_testing_inline.rb +0 -92
- data/test/test_util.rb +0 -18
- data/test/test_web.rb +0 -372
- data/web/assets/images/bootstrap/glyphicons-halflings-white.png +0 -0
- data/web/assets/images/bootstrap/glyphicons-halflings.png +0 -0
- data/web/assets/images/status/active.png +0 -0
- data/web/assets/images/status/idle.png +0 -0
- data/web/assets/javascripts/locales/README.md +0 -27
- data/web/assets/javascripts/locales/jquery.timeago.ar.js +0 -96
- data/web/assets/javascripts/locales/jquery.timeago.bg.js +0 -18
- data/web/assets/javascripts/locales/jquery.timeago.bs.js +0 -49
- data/web/assets/javascripts/locales/jquery.timeago.ca.js +0 -18
- data/web/assets/javascripts/locales/jquery.timeago.cy.js +0 -20
- data/web/assets/javascripts/locales/jquery.timeago.cz.js +0 -18
- data/web/assets/javascripts/locales/jquery.timeago.da.js +0 -18
- data/web/assets/javascripts/locales/jquery.timeago.de.js +0 -18
- data/web/assets/javascripts/locales/jquery.timeago.el.js +0 -18
- data/web/assets/javascripts/locales/jquery.timeago.en-short.js +0 -20
- data/web/assets/javascripts/locales/jquery.timeago.en.js +0 -20
- data/web/assets/javascripts/locales/jquery.timeago.es.js +0 -18
- data/web/assets/javascripts/locales/jquery.timeago.et.js +0 -18
- data/web/assets/javascripts/locales/jquery.timeago.fa.js +0 -22
- data/web/assets/javascripts/locales/jquery.timeago.fi.js +0 -28
- data/web/assets/javascripts/locales/jquery.timeago.fr-short.js +0 -16
- data/web/assets/javascripts/locales/jquery.timeago.fr.js +0 -17
- data/web/assets/javascripts/locales/jquery.timeago.he.js +0 -18
- data/web/assets/javascripts/locales/jquery.timeago.hr.js +0 -49
- data/web/assets/javascripts/locales/jquery.timeago.hu.js +0 -18
- data/web/assets/javascripts/locales/jquery.timeago.hy.js +0 -18
- data/web/assets/javascripts/locales/jquery.timeago.id.js +0 -18
- data/web/assets/javascripts/locales/jquery.timeago.it.js +0 -16
- data/web/assets/javascripts/locales/jquery.timeago.ja.js +0 -19
- data/web/assets/javascripts/locales/jquery.timeago.ko.js +0 -17
- data/web/assets/javascripts/locales/jquery.timeago.lt.js +0 -20
- data/web/assets/javascripts/locales/jquery.timeago.mk.js +0 -20
- data/web/assets/javascripts/locales/jquery.timeago.nl.js +0 -20
- data/web/assets/javascripts/locales/jquery.timeago.no.js +0 -18
- data/web/assets/javascripts/locales/jquery.timeago.pl.js +0 -31
- data/web/assets/javascripts/locales/jquery.timeago.pt-br.js +0 -16
- data/web/assets/javascripts/locales/jquery.timeago.pt.js +0 -16
- data/web/assets/javascripts/locales/jquery.timeago.ro.js +0 -18
- data/web/assets/javascripts/locales/jquery.timeago.rs.js +0 -49
- data/web/assets/javascripts/locales/jquery.timeago.ru.js +0 -34
- data/web/assets/javascripts/locales/jquery.timeago.sk.js +0 -18
- data/web/assets/javascripts/locales/jquery.timeago.sl.js +0 -44
- data/web/assets/javascripts/locales/jquery.timeago.sv.js +0 -18
- data/web/assets/javascripts/locales/jquery.timeago.th.js +0 -20
- data/web/assets/javascripts/locales/jquery.timeago.tr.js +0 -16
- data/web/assets/javascripts/locales/jquery.timeago.uk.js +0 -34
- data/web/assets/javascripts/locales/jquery.timeago.uz.js +0 -19
- data/web/assets/javascripts/locales/jquery.timeago.zh-CN.js +0 -20
- data/web/assets/javascripts/locales/jquery.timeago.zh-TW.js +0 -20
- data/web/views/_poll.erb +0 -14
- data/web/views/_workers.erb +0 -29
- data/web/views/index.erb +0 -16
data/test/test_processor.rb
DELETED
@@ -1,160 +0,0 @@
|
|
1
|
-
require 'helper'
|
2
|
-
require 'sidekiq/processor'
|
3
|
-
|
4
|
-
class TestProcessor < Sidekiq::Test
|
5
|
-
TestException = Class.new(StandardError)
|
6
|
-
TEST_EXCEPTION = TestException.new("kerboom!")
|
7
|
-
|
8
|
-
describe 'with mock setup' do
|
9
|
-
before do
|
10
|
-
$invokes = 0
|
11
|
-
@boss = Minitest::Mock.new
|
12
|
-
@processor = ::Sidekiq::Processor.new(@boss)
|
13
|
-
Celluloid.logger = nil
|
14
|
-
Sidekiq.redis = REDIS
|
15
|
-
end
|
16
|
-
|
17
|
-
class MockWorker
|
18
|
-
include Sidekiq::Worker
|
19
|
-
def perform(args)
|
20
|
-
raise TEST_EXCEPTION if args == 'boom'
|
21
|
-
args.pop if args.is_a? Array
|
22
|
-
$invokes += 1
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
def work(msg, queue='queue:default')
|
27
|
-
Sidekiq::BasicFetch::UnitOfWork.new(queue, msg)
|
28
|
-
end
|
29
|
-
|
30
|
-
it 'processes as expected' do
|
31
|
-
msg = Sidekiq.dump_json({ 'class' => MockWorker.to_s, 'args' => ['myarg'] })
|
32
|
-
actor = Minitest::Mock.new
|
33
|
-
actor.expect(:processor_done, nil, [@processor])
|
34
|
-
actor.expect(:real_thread, nil, [nil, Celluloid::Thread])
|
35
|
-
@boss.expect(:async, actor, [])
|
36
|
-
@boss.expect(:async, actor, [])
|
37
|
-
@processor.process(work(msg))
|
38
|
-
@boss.verify
|
39
|
-
assert_equal 1, $invokes
|
40
|
-
end
|
41
|
-
|
42
|
-
it 'passes exceptions to ExceptionHandler' do
|
43
|
-
actor = Minitest::Mock.new
|
44
|
-
actor.expect(:real_thread, nil, [nil, Celluloid::Thread])
|
45
|
-
@boss.expect(:async, actor, [])
|
46
|
-
msg = Sidekiq.dump_json({ 'class' => MockWorker.to_s, 'args' => ['boom'] })
|
47
|
-
begin
|
48
|
-
@processor.process(work(msg))
|
49
|
-
flunk "Expected #process to raise exception"
|
50
|
-
rescue TestException
|
51
|
-
end
|
52
|
-
|
53
|
-
assert_equal 0, $invokes
|
54
|
-
end
|
55
|
-
|
56
|
-
it 're-raises exceptions after handling' do
|
57
|
-
msg = Sidekiq.dump_json({ 'class' => MockWorker.to_s, 'args' => ['boom'] })
|
58
|
-
re_raise = false
|
59
|
-
actor = Minitest::Mock.new
|
60
|
-
actor.expect(:real_thread, nil, [nil, Celluloid::Thread])
|
61
|
-
@boss.expect(:async, actor, [])
|
62
|
-
|
63
|
-
begin
|
64
|
-
@processor.process(work(msg))
|
65
|
-
rescue TestException
|
66
|
-
re_raise = true
|
67
|
-
end
|
68
|
-
|
69
|
-
assert re_raise, "does not re-raise exceptions after handling"
|
70
|
-
end
|
71
|
-
|
72
|
-
it 'does not modify original arguments' do
|
73
|
-
msg = { 'class' => MockWorker.to_s, 'args' => [['myarg']] }
|
74
|
-
msgstr = Sidekiq.dump_json(msg)
|
75
|
-
processor = ::Sidekiq::Processor.new(@boss)
|
76
|
-
actor = Minitest::Mock.new
|
77
|
-
actor.expect(:processor_done, nil, [processor])
|
78
|
-
actor.expect(:real_thread, nil, [nil, Celluloid::Thread])
|
79
|
-
@boss.expect(:async, actor, [])
|
80
|
-
@boss.expect(:async, actor, [])
|
81
|
-
processor.process(work(msgstr))
|
82
|
-
assert_equal [['myarg']], msg['args']
|
83
|
-
end
|
84
|
-
|
85
|
-
describe 'stats' do
|
86
|
-
before do
|
87
|
-
Sidekiq.redis {|c| c.flushdb }
|
88
|
-
end
|
89
|
-
|
90
|
-
def with_expire(time)
|
91
|
-
begin
|
92
|
-
old = Sidekiq::Processor::STATS_TIMEOUT
|
93
|
-
silence_warnings { Sidekiq::Processor.const_set(:STATS_TIMEOUT, time) }
|
94
|
-
yield
|
95
|
-
ensure
|
96
|
-
silence_warnings { Sidekiq::Processor.const_set(:STATS_TIMEOUT, old) }
|
97
|
-
end
|
98
|
-
end
|
99
|
-
|
100
|
-
describe 'when successful' do
|
101
|
-
let(:processed_today_key) { "stat:processed:#{Time.now.utc.to_date}" }
|
102
|
-
|
103
|
-
def successful_job
|
104
|
-
msg = Sidekiq.dump_json({ 'class' => MockWorker.to_s, 'args' => ['myarg'] })
|
105
|
-
actor = Minitest::Mock.new
|
106
|
-
actor.expect(:real_thread, nil, [nil, Celluloid::Thread])
|
107
|
-
actor.expect(:processor_done, nil, [@processor])
|
108
|
-
@boss.expect(:async, actor, [])
|
109
|
-
@boss.expect(:async, actor, [])
|
110
|
-
@processor.process(work(msg))
|
111
|
-
end
|
112
|
-
|
113
|
-
it 'increments processed stat' do
|
114
|
-
successful_job
|
115
|
-
assert_equal 1, Sidekiq::Stats.new.processed
|
116
|
-
end
|
117
|
-
|
118
|
-
it 'expires processed stat' do
|
119
|
-
successful_job
|
120
|
-
assert_equal Sidekiq::Processor::STATS_TIMEOUT, Sidekiq.redis { |conn| conn.ttl(processed_today_key) }
|
121
|
-
end
|
122
|
-
|
123
|
-
it 'increments date processed stat' do
|
124
|
-
successful_job
|
125
|
-
assert_equal 1, Sidekiq.redis { |conn| conn.get(processed_today_key) }.to_i
|
126
|
-
end
|
127
|
-
end
|
128
|
-
|
129
|
-
describe 'when failed' do
|
130
|
-
let(:failed_today_key) { "stat:failed:#{Time.now.utc.to_date}" }
|
131
|
-
|
132
|
-
def failed_job
|
133
|
-
actor = Minitest::Mock.new
|
134
|
-
actor.expect(:real_thread, nil, [nil, Celluloid::Thread])
|
135
|
-
@boss.expect(:async, actor, [])
|
136
|
-
msg = Sidekiq.dump_json({ 'class' => MockWorker.to_s, 'args' => ['boom'] })
|
137
|
-
begin
|
138
|
-
@processor.process(work(msg))
|
139
|
-
rescue TestException
|
140
|
-
end
|
141
|
-
end
|
142
|
-
|
143
|
-
it 'increments failed stat' do
|
144
|
-
failed_job
|
145
|
-
assert_equal 1, Sidekiq::Stats.new.failed
|
146
|
-
end
|
147
|
-
|
148
|
-
it 'increments date failed stat' do
|
149
|
-
failed_job
|
150
|
-
assert_equal 1, Sidekiq.redis { |conn| conn.get(failed_today_key) }.to_i
|
151
|
-
end
|
152
|
-
|
153
|
-
it 'expires failed stat' do
|
154
|
-
failed_job
|
155
|
-
assert_equal Sidekiq::Processor::STATS_TIMEOUT, Sidekiq.redis { |conn| conn.ttl(failed_today_key) }
|
156
|
-
end
|
157
|
-
end
|
158
|
-
end
|
159
|
-
end
|
160
|
-
end
|
@@ -1,97 +0,0 @@
|
|
1
|
-
require 'helper'
|
2
|
-
require 'sidekiq/redis_connection'
|
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" do
|
31
|
-
pool = Sidekiq::RedisConnection.create(:namespace => "xxx")
|
32
|
-
assert_equal "xxx", pool.checkout.namespace
|
33
|
-
end
|
34
|
-
|
35
|
-
it "uses given :namespace over :namespace from Sidekiq.options" do
|
36
|
-
Sidekiq.options[:namespace] = "xxx"
|
37
|
-
pool = Sidekiq::RedisConnection.create(:namespace => "yyy")
|
38
|
-
assert_equal "yyy", pool.checkout.namespace
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
describe "pool_timeout" do
|
43
|
-
it "uses a given :timeout over the default of 1" do
|
44
|
-
pool = Sidekiq::RedisConnection.create(:pool_timeout => 5)
|
45
|
-
|
46
|
-
assert_equal 5, pool.instance_eval{ @timeout }
|
47
|
-
end
|
48
|
-
|
49
|
-
it "uses the default timeout of 1 if no override" do
|
50
|
-
pool = Sidekiq::RedisConnection.create
|
51
|
-
|
52
|
-
assert_equal 1, pool.instance_eval{ @timeout }
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
describe ".determine_redis_provider" do
|
58
|
-
|
59
|
-
def with_env_var(var, uri, skip_provider=false)
|
60
|
-
vars = ['REDISTOGO_URL', 'REDIS_PROVIDER', 'REDIS_URL'] - [var]
|
61
|
-
vars.each do |v|
|
62
|
-
next if skip_provider
|
63
|
-
ENV[v] = nil
|
64
|
-
end
|
65
|
-
ENV[var] = uri
|
66
|
-
assert_equal uri, Sidekiq::RedisConnection.send(:determine_redis_provider)
|
67
|
-
ENV[var] = nil
|
68
|
-
end
|
69
|
-
|
70
|
-
describe "with REDISTOGO_URL set" do
|
71
|
-
it "sets connection URI to RedisToGo" do
|
72
|
-
with_env_var 'REDISTOGO_URL', 'redis://redis-to-go:6379/0'
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
describe "with REDIS_PROVIDER set" do
|
77
|
-
it "sets connection URI to the provider" do
|
78
|
-
uri = 'redis://sidekiq-redis-provider:6379/0'
|
79
|
-
provider = 'SIDEKIQ_REDIS_PROVIDER'
|
80
|
-
|
81
|
-
ENV['REDIS_PROVIDER'] = provider
|
82
|
-
ENV[provider] = uri
|
83
|
-
|
84
|
-
with_env_var provider, uri, true
|
85
|
-
|
86
|
-
ENV[provider] = nil
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
|
-
describe "with REDIS_URL set" do
|
91
|
-
it "sets connection URI to custom uri" do
|
92
|
-
with_env_var 'REDIS_URL', 'redis://redis-uri:6379/0'
|
93
|
-
end
|
94
|
-
end
|
95
|
-
|
96
|
-
end
|
97
|
-
end
|
data/test/test_retry.rb
DELETED
@@ -1,306 +0,0 @@
|
|
1
|
-
require 'helper'
|
2
|
-
require 'sidekiq/scheduled'
|
3
|
-
require 'sidekiq/middleware/server/retry_jobs'
|
4
|
-
|
5
|
-
class TestRetry < Sidekiq::Test
|
6
|
-
describe 'middleware' do
|
7
|
-
before do
|
8
|
-
@redis = Minitest::Mock.new
|
9
|
-
# Ugh, this is terrible.
|
10
|
-
Sidekiq.instance_variable_set(:@redis, @redis)
|
11
|
-
|
12
|
-
def @redis.with; yield self; end
|
13
|
-
end
|
14
|
-
|
15
|
-
let(:worker) do
|
16
|
-
Class.new do
|
17
|
-
include ::Sidekiq::Worker
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
it 'allows disabling retry' do
|
22
|
-
msg = { 'class' => 'Bob', 'args' => [1,2,'foo'], 'retry' => false }
|
23
|
-
msg2 = msg.dup
|
24
|
-
handler = Sidekiq::Middleware::Server::RetryJobs.new
|
25
|
-
assert_raises RuntimeError do
|
26
|
-
handler.call(worker, msg2, 'default') do
|
27
|
-
raise "kerblammo!"
|
28
|
-
end
|
29
|
-
end
|
30
|
-
assert_equal msg, msg2
|
31
|
-
end
|
32
|
-
|
33
|
-
it 'allows a numeric retry' do
|
34
|
-
@redis.expect :zadd, 1, ['retry', String, String]
|
35
|
-
msg = { 'class' => 'Bob', 'args' => [1,2,'foo'], 'retry' => 2 }
|
36
|
-
msg2 = msg.dup
|
37
|
-
handler = Sidekiq::Middleware::Server::RetryJobs.new
|
38
|
-
assert_raises RuntimeError do
|
39
|
-
handler.call(worker, msg2, 'default') do
|
40
|
-
raise "kerblammo!"
|
41
|
-
end
|
42
|
-
end
|
43
|
-
msg2.delete('failed_at')
|
44
|
-
assert_equal({"class"=>"Bob", "args"=>[1, 2, "foo"], "retry"=>2, "queue"=>"default", "error_message"=>"kerblammo!", "error_class"=>"RuntimeError", "retry_count"=>0}, msg2)
|
45
|
-
@redis.verify
|
46
|
-
end
|
47
|
-
|
48
|
-
it 'allows a max_retries option in initializer' do
|
49
|
-
max_retries = 7
|
50
|
-
1.upto(max_retries) do
|
51
|
-
@redis.expect :zadd, 1, ['retry', String, String]
|
52
|
-
end
|
53
|
-
msg = { 'class' => 'Bob', 'args' => [1,2,'foo'], 'retry' => true }
|
54
|
-
handler = Sidekiq::Middleware::Server::RetryJobs.new({:max_retries => max_retries})
|
55
|
-
1.upto(max_retries + 1) do
|
56
|
-
assert_raises RuntimeError do
|
57
|
-
handler.call(worker, msg, 'default') do
|
58
|
-
raise "kerblammo!"
|
59
|
-
end
|
60
|
-
end
|
61
|
-
end
|
62
|
-
@redis.verify
|
63
|
-
end
|
64
|
-
|
65
|
-
it 'saves backtraces' do
|
66
|
-
@redis.expect :zadd, 1, ['retry', String, String]
|
67
|
-
msg = { 'class' => 'Bob', 'args' => [1,2,'foo'], 'retry' => true, 'backtrace' => true }
|
68
|
-
handler = Sidekiq::Middleware::Server::RetryJobs.new
|
69
|
-
c = nil
|
70
|
-
assert_raises RuntimeError do
|
71
|
-
handler.call(worker, msg, 'default') do
|
72
|
-
c = caller(0); raise "kerblammo!"
|
73
|
-
end
|
74
|
-
end
|
75
|
-
assert msg["error_backtrace"]
|
76
|
-
assert_equal c[0], msg["error_backtrace"][0]
|
77
|
-
@redis.verify
|
78
|
-
end
|
79
|
-
|
80
|
-
it 'saves partial backtraces' do
|
81
|
-
@redis.expect :zadd, 1, ['retry', String, String]
|
82
|
-
msg = { 'class' => 'Bob', 'args' => [1,2,'foo'], 'retry' => true, 'backtrace' => 3 }
|
83
|
-
handler = Sidekiq::Middleware::Server::RetryJobs.new
|
84
|
-
c = nil
|
85
|
-
assert_raises RuntimeError do
|
86
|
-
handler.call(worker, msg, 'default') do
|
87
|
-
c = caller(0)[0..3]; raise "kerblammo!"
|
88
|
-
end
|
89
|
-
end
|
90
|
-
assert msg["error_backtrace"]
|
91
|
-
assert_equal c, msg["error_backtrace"]
|
92
|
-
end
|
93
|
-
|
94
|
-
it 'handles a new failed message' do
|
95
|
-
@redis.expect :zadd, 1, ['retry', String, String]
|
96
|
-
msg = { 'class' => 'Bob', 'args' => [1,2,'foo'], 'retry' => true }
|
97
|
-
handler = Sidekiq::Middleware::Server::RetryJobs.new
|
98
|
-
assert_raises RuntimeError do
|
99
|
-
handler.call(worker, msg, 'default') do
|
100
|
-
raise "kerblammo!"
|
101
|
-
end
|
102
|
-
end
|
103
|
-
assert_equal 'default', msg["queue"]
|
104
|
-
assert_equal 'kerblammo!', msg["error_message"]
|
105
|
-
assert_equal 'RuntimeError', msg["error_class"]
|
106
|
-
assert_equal 0, msg["retry_count"]
|
107
|
-
refute msg["error_backtrace"]
|
108
|
-
assert msg["failed_at"]
|
109
|
-
@redis.verify
|
110
|
-
end
|
111
|
-
|
112
|
-
it 'allows a retry queue' do
|
113
|
-
@redis.expect :zadd, 1, ['retry', String, String]
|
114
|
-
msg = { 'class' => 'Bob', 'args' => [1,2,'foo'], 'retry' => true, 'retry_queue' => 'retry' }
|
115
|
-
handler = Sidekiq::Middleware::Server::RetryJobs.new
|
116
|
-
assert_raises RuntimeError do
|
117
|
-
handler.call(worker, msg, 'default') do
|
118
|
-
raise "kerblammo!"
|
119
|
-
end
|
120
|
-
end
|
121
|
-
assert_equal 'retry', msg["queue"]
|
122
|
-
assert_equal 'kerblammo!', msg["error_message"]
|
123
|
-
assert_equal 'RuntimeError', msg["error_class"]
|
124
|
-
assert_equal 0, msg["retry_count"]
|
125
|
-
refute msg["error_backtrace"]
|
126
|
-
assert msg["failed_at"]
|
127
|
-
@redis.verify
|
128
|
-
end
|
129
|
-
|
130
|
-
it 'handles a recurring failed message' do
|
131
|
-
@redis.expect :zadd, 1, ['retry', String, String]
|
132
|
-
now = Time.now.utc
|
133
|
-
msg = {"class"=>"Bob", "args"=>[1, 2, "foo"], 'retry' => true, "queue"=>"default", "error_message"=>"kerblammo!", "error_class"=>"RuntimeError", "failed_at"=>now, "retry_count"=>10}
|
134
|
-
handler = Sidekiq::Middleware::Server::RetryJobs.new
|
135
|
-
assert_raises RuntimeError do
|
136
|
-
handler.call(worker, msg, 'default') do
|
137
|
-
raise "kerblammo!"
|
138
|
-
end
|
139
|
-
end
|
140
|
-
assert_equal 'default', msg["queue"]
|
141
|
-
assert_equal 'kerblammo!', msg["error_message"]
|
142
|
-
assert_equal 'RuntimeError', msg["error_class"]
|
143
|
-
assert_equal 11, msg["retry_count"]
|
144
|
-
assert msg["failed_at"]
|
145
|
-
@redis.verify
|
146
|
-
end
|
147
|
-
|
148
|
-
it 'handles a recurring failed message before reaching user-specifed max' do
|
149
|
-
@redis.expect :zadd, 1, ['retry', String, String]
|
150
|
-
now = Time.now.utc
|
151
|
-
msg = {"class"=>"Bob", "args"=>[1, 2, "foo"], 'retry' => 10, "queue"=>"default", "error_message"=>"kerblammo!", "error_class"=>"RuntimeError", "failed_at"=>now, "retry_count"=>8}
|
152
|
-
handler = Sidekiq::Middleware::Server::RetryJobs.new
|
153
|
-
assert_raises RuntimeError do
|
154
|
-
handler.call(worker, msg, 'default') do
|
155
|
-
raise "kerblammo!"
|
156
|
-
end
|
157
|
-
end
|
158
|
-
assert_equal 'default', msg["queue"]
|
159
|
-
assert_equal 'kerblammo!', msg["error_message"]
|
160
|
-
assert_equal 'RuntimeError', msg["error_class"]
|
161
|
-
assert_equal 9, msg["retry_count"]
|
162
|
-
assert msg["failed_at"]
|
163
|
-
@redis.verify
|
164
|
-
end
|
165
|
-
|
166
|
-
it 'throws away old messages after too many retries (using the default)' do
|
167
|
-
now = Time.now.utc
|
168
|
-
msg = {"class"=>"Bob", "args"=>[1, 2, "foo"], "queue"=>"default", "error_message"=>"kerblammo!", "error_class"=>"RuntimeError", "failed_at"=>now, "retry"=>true, "retry_count"=>25}
|
169
|
-
@redis.expect :zadd, 1, [ 'retry', String, String ]
|
170
|
-
handler = Sidekiq::Middleware::Server::RetryJobs.new
|
171
|
-
assert_raises RuntimeError do
|
172
|
-
handler.call(worker, msg, 'default') do
|
173
|
-
raise "kerblammo!"
|
174
|
-
end
|
175
|
-
end
|
176
|
-
# Minitest can't assert that a method call did NOT happen!?
|
177
|
-
assert_raises(MockExpectationError) { @redis.verify }
|
178
|
-
end
|
179
|
-
|
180
|
-
it 'throws away old messages after too many retries (using user-specified max)' do
|
181
|
-
now = Time.now.utc
|
182
|
-
msg = {"class"=>"Bob", "args"=>[1, 2, "foo"], "queue"=>"default", "error_message"=>"kerblammo!", "error_class"=>"RuntimeError", "failed_at"=>now, "retry"=>3, "retry_count"=>3}
|
183
|
-
@redis.expect :zadd, 1, [ 'retry', String, String ]
|
184
|
-
handler = Sidekiq::Middleware::Server::RetryJobs.new
|
185
|
-
assert_raises RuntimeError do
|
186
|
-
handler.call(worker, msg, 'default') do
|
187
|
-
raise "kerblammo!"
|
188
|
-
end
|
189
|
-
end
|
190
|
-
# Minitest can't assert that a method call did NOT happen!?
|
191
|
-
assert_raises(MockExpectationError) { @redis.verify }
|
192
|
-
end
|
193
|
-
|
194
|
-
describe "retry exhaustion" do
|
195
|
-
let(:handler){ Sidekiq::Middleware::Server::RetryJobs.new }
|
196
|
-
let(:worker) { Minitest::Mock.new }
|
197
|
-
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} }
|
198
|
-
|
199
|
-
describe "worker method" do
|
200
|
-
let(:worker) do
|
201
|
-
klass = Class.new do
|
202
|
-
include Sidekiq::Worker
|
203
|
-
|
204
|
-
def self.name; "Worker"; end
|
205
|
-
|
206
|
-
def retries_exhausted(*args)
|
207
|
-
args << "retried_method"
|
208
|
-
end
|
209
|
-
end
|
210
|
-
end
|
211
|
-
|
212
|
-
it 'calls worker.retries_exhausted after too many retries' do
|
213
|
-
assert_equal [1,2, "foo", "retried_method"], handler.retries_exhausted(worker.new, msg)
|
214
|
-
end
|
215
|
-
end
|
216
|
-
|
217
|
-
describe "worker block" do
|
218
|
-
let(:worker) do
|
219
|
-
Class.new do
|
220
|
-
include Sidekiq::Worker
|
221
|
-
|
222
|
-
sidekiq_retries_exhausted do |msg|
|
223
|
-
msg.tap {|m| m['called_by_callback'] = true }
|
224
|
-
end
|
225
|
-
end
|
226
|
-
end
|
227
|
-
|
228
|
-
it 'calls worker sidekiq_retries_exhausted_block after too many retries' do
|
229
|
-
new_msg = handler.retries_exhausted(worker.new, msg)
|
230
|
-
expected_msg = msg.merge('called_by_callback' => true)
|
231
|
-
|
232
|
-
assert_equal expected_msg, new_msg, "sidekiq_retries_exhausted block not called"
|
233
|
-
end
|
234
|
-
end
|
235
|
-
|
236
|
-
it 'handles and logs retries_exhausted failures gracefully (drops them)' do
|
237
|
-
def worker.retries_exhausted(*args)
|
238
|
-
raise 'bam!'
|
239
|
-
end
|
240
|
-
|
241
|
-
e = task_misbehaving_worker
|
242
|
-
assert_equal e.message, "kerblammo!"
|
243
|
-
worker.verify
|
244
|
-
end
|
245
|
-
|
246
|
-
def task_misbehaving_worker
|
247
|
-
assert_raises RuntimeError do
|
248
|
-
handler.call(worker, msg, 'default') do
|
249
|
-
raise 'kerblammo!'
|
250
|
-
end
|
251
|
-
end
|
252
|
-
end
|
253
|
-
end
|
254
|
-
|
255
|
-
describe "custom retry delay" do
|
256
|
-
before do
|
257
|
-
@old_logger = Sidekiq.logger
|
258
|
-
@tmp_log_path = '/tmp/sidekiq-retries.log'
|
259
|
-
Sidekiq.logger = Logger.new(@tmp_log_path)
|
260
|
-
end
|
261
|
-
|
262
|
-
after do
|
263
|
-
Sidekiq.logger = @old_logger
|
264
|
-
Sidekiq.options.delete(:logfile)
|
265
|
-
File.unlink @tmp_log_path if File.exists?(@tmp_log_path)
|
266
|
-
end
|
267
|
-
|
268
|
-
let(:custom_worker) do
|
269
|
-
Class.new do
|
270
|
-
include ::Sidekiq::Worker
|
271
|
-
|
272
|
-
sidekiq_retry_in do |count|
|
273
|
-
count * 2
|
274
|
-
end
|
275
|
-
end
|
276
|
-
end
|
277
|
-
|
278
|
-
let(:error_worker) do
|
279
|
-
Class.new do
|
280
|
-
include ::Sidekiq::Worker
|
281
|
-
|
282
|
-
sidekiq_retry_in do |count|
|
283
|
-
count / 0
|
284
|
-
end
|
285
|
-
end
|
286
|
-
end
|
287
|
-
|
288
|
-
let(:handler) { Sidekiq::Middleware::Server::RetryJobs.new }
|
289
|
-
|
290
|
-
it "retries with a default delay" do
|
291
|
-
refute_equal 4, handler.delay_for(worker, 2)
|
292
|
-
end
|
293
|
-
|
294
|
-
it "retries with a custom delay" do
|
295
|
-
assert_equal 4, handler.delay_for(custom_worker, 2)
|
296
|
-
end
|
297
|
-
|
298
|
-
it "falls back to the default retry on exception" do
|
299
|
-
refute_equal 4, handler.delay_for(error_worker, 2)
|
300
|
-
assert_match(/Failure scheduling retry using the defined `sidekiq_retry_in`/,
|
301
|
-
File.read(@tmp_log_path), 'Log entry missing for sidekiq_retry_in')
|
302
|
-
end
|
303
|
-
end
|
304
|
-
end
|
305
|
-
|
306
|
-
end
|