sidekiq 4.0.0 → 5.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.

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