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.

Files changed (187) hide show
  1. checksums.yaml +7 -0
  2. data/.github/contributing.md +32 -0
  3. data/.github/issue_template.md +9 -0
  4. data/.gitignore +1 -0
  5. data/.travis.yml +16 -17
  6. data/3.0-Upgrade.md +70 -0
  7. data/4.0-Upgrade.md +53 -0
  8. data/COMM-LICENSE +56 -44
  9. data/Changes.md +644 -1
  10. data/Ent-Changes.md +173 -0
  11. data/Gemfile +27 -0
  12. data/LICENSE +1 -1
  13. data/Pro-2.0-Upgrade.md +138 -0
  14. data/Pro-3.0-Upgrade.md +44 -0
  15. data/Pro-Changes.md +457 -3
  16. data/README.md +46 -29
  17. data/Rakefile +6 -3
  18. data/bin/sidekiq +4 -0
  19. data/bin/sidekiqctl +41 -20
  20. data/bin/sidekiqload +154 -0
  21. data/code_of_conduct.md +50 -0
  22. data/lib/generators/sidekiq/templates/worker.rb.erb +9 -0
  23. data/lib/generators/sidekiq/templates/worker_spec.rb.erb +6 -0
  24. data/lib/generators/sidekiq/templates/worker_test.rb.erb +8 -0
  25. data/lib/generators/sidekiq/worker_generator.rb +49 -0
  26. data/lib/sidekiq.rb +141 -29
  27. data/lib/sidekiq/api.rb +540 -106
  28. data/lib/sidekiq/cli.rb +131 -71
  29. data/lib/sidekiq/client.rb +168 -96
  30. data/lib/sidekiq/core_ext.rb +36 -8
  31. data/lib/sidekiq/exception_handler.rb +20 -28
  32. data/lib/sidekiq/extensions/action_mailer.rb +25 -5
  33. data/lib/sidekiq/extensions/active_record.rb +8 -4
  34. data/lib/sidekiq/extensions/class_methods.rb +9 -5
  35. data/lib/sidekiq/extensions/generic_proxy.rb +1 -0
  36. data/lib/sidekiq/fetch.rb +45 -101
  37. data/lib/sidekiq/launcher.rb +144 -30
  38. data/lib/sidekiq/logging.rb +69 -12
  39. data/lib/sidekiq/manager.rb +90 -140
  40. data/lib/sidekiq/middleware/chain.rb +18 -5
  41. data/lib/sidekiq/middleware/i18n.rb +9 -2
  42. data/lib/sidekiq/middleware/server/active_record.rb +1 -1
  43. data/lib/sidekiq/middleware/server/logging.rb +11 -11
  44. data/lib/sidekiq/middleware/server/retry_jobs.rb +98 -44
  45. data/lib/sidekiq/paginator.rb +20 -8
  46. data/lib/sidekiq/processor.rb +157 -96
  47. data/lib/sidekiq/rails.rb +109 -5
  48. data/lib/sidekiq/redis_connection.rb +70 -24
  49. data/lib/sidekiq/scheduled.rb +122 -50
  50. data/lib/sidekiq/testing.rb +171 -31
  51. data/lib/sidekiq/testing/inline.rb +1 -0
  52. data/lib/sidekiq/util.rb +31 -5
  53. data/lib/sidekiq/version.rb +2 -1
  54. data/lib/sidekiq/web.rb +136 -263
  55. data/lib/sidekiq/web/action.rb +93 -0
  56. data/lib/sidekiq/web/application.rb +336 -0
  57. data/lib/sidekiq/web/helpers.rb +278 -0
  58. data/lib/sidekiq/web/router.rb +100 -0
  59. data/lib/sidekiq/worker.rb +40 -7
  60. data/sidekiq.gemspec +18 -14
  61. data/web/assets/images/favicon.ico +0 -0
  62. data/web/assets/images/{status-sd8051fd480.png → status.png} +0 -0
  63. data/web/assets/javascripts/application.js +67 -19
  64. data/web/assets/javascripts/dashboard.js +138 -29
  65. data/web/assets/stylesheets/application.css +267 -406
  66. data/web/assets/stylesheets/bootstrap.css +4 -8
  67. data/web/locales/cs.yml +78 -0
  68. data/web/locales/da.yml +9 -1
  69. data/web/locales/de.yml +18 -9
  70. data/web/locales/el.yml +68 -0
  71. data/web/locales/en.yml +19 -4
  72. data/web/locales/es.yml +10 -1
  73. data/web/locales/fa.yml +79 -0
  74. data/web/locales/fr.yml +50 -32
  75. data/web/locales/hi.yml +75 -0
  76. data/web/locales/it.yml +27 -18
  77. data/web/locales/ja.yml +27 -12
  78. data/web/locales/ko.yml +8 -3
  79. data/web/locales/{no.yml → nb.yml} +19 -5
  80. data/web/locales/nl.yml +8 -3
  81. data/web/locales/pl.yml +0 -1
  82. data/web/locales/pt-br.yml +11 -4
  83. data/web/locales/pt.yml +8 -1
  84. data/web/locales/ru.yml +39 -21
  85. data/web/locales/sv.yml +68 -0
  86. data/web/locales/ta.yml +75 -0
  87. data/web/locales/uk.yml +76 -0
  88. data/web/locales/zh-cn.yml +68 -0
  89. data/web/locales/zh-tw.yml +68 -0
  90. data/web/views/_footer.erb +17 -0
  91. data/web/views/_job_info.erb +72 -60
  92. data/web/views/_nav.erb +58 -25
  93. data/web/views/_paging.erb +5 -5
  94. data/web/views/_poll_link.erb +7 -0
  95. data/web/views/_summary.erb +20 -14
  96. data/web/views/busy.erb +94 -0
  97. data/web/views/dashboard.erb +34 -21
  98. data/web/views/dead.erb +34 -0
  99. data/web/views/layout.erb +8 -30
  100. data/web/views/morgue.erb +75 -0
  101. data/web/views/queue.erb +37 -30
  102. data/web/views/queues.erb +26 -20
  103. data/web/views/retries.erb +60 -47
  104. data/web/views/retry.erb +23 -19
  105. data/web/views/scheduled.erb +39 -35
  106. data/web/views/scheduled_job_info.erb +2 -1
  107. metadata +152 -195
  108. data/Contributing.md +0 -29
  109. data/config.ru +0 -18
  110. data/lib/sidekiq/actor.rb +0 -7
  111. data/lib/sidekiq/capistrano.rb +0 -54
  112. data/lib/sidekiq/yaml_patch.rb +0 -21
  113. data/test/config.yml +0 -11
  114. data/test/env_based_config.yml +0 -11
  115. data/test/fake_env.rb +0 -0
  116. data/test/helper.rb +0 -42
  117. data/test/test_api.rb +0 -341
  118. data/test/test_cli.rb +0 -326
  119. data/test/test_client.rb +0 -211
  120. data/test/test_exception_handler.rb +0 -124
  121. data/test/test_extensions.rb +0 -105
  122. data/test/test_fetch.rb +0 -44
  123. data/test/test_manager.rb +0 -83
  124. data/test/test_middleware.rb +0 -135
  125. data/test/test_processor.rb +0 -160
  126. data/test/test_redis_connection.rb +0 -97
  127. data/test/test_retry.rb +0 -306
  128. data/test/test_scheduled.rb +0 -86
  129. data/test/test_scheduling.rb +0 -47
  130. data/test/test_sidekiq.rb +0 -37
  131. data/test/test_testing.rb +0 -82
  132. data/test/test_testing_fake.rb +0 -265
  133. data/test/test_testing_inline.rb +0 -92
  134. data/test/test_util.rb +0 -18
  135. data/test/test_web.rb +0 -372
  136. data/web/assets/images/bootstrap/glyphicons-halflings-white.png +0 -0
  137. data/web/assets/images/bootstrap/glyphicons-halflings.png +0 -0
  138. data/web/assets/images/status/active.png +0 -0
  139. data/web/assets/images/status/idle.png +0 -0
  140. data/web/assets/javascripts/locales/README.md +0 -27
  141. data/web/assets/javascripts/locales/jquery.timeago.ar.js +0 -96
  142. data/web/assets/javascripts/locales/jquery.timeago.bg.js +0 -18
  143. data/web/assets/javascripts/locales/jquery.timeago.bs.js +0 -49
  144. data/web/assets/javascripts/locales/jquery.timeago.ca.js +0 -18
  145. data/web/assets/javascripts/locales/jquery.timeago.cy.js +0 -20
  146. data/web/assets/javascripts/locales/jquery.timeago.cz.js +0 -18
  147. data/web/assets/javascripts/locales/jquery.timeago.da.js +0 -18
  148. data/web/assets/javascripts/locales/jquery.timeago.de.js +0 -18
  149. data/web/assets/javascripts/locales/jquery.timeago.el.js +0 -18
  150. data/web/assets/javascripts/locales/jquery.timeago.en-short.js +0 -20
  151. data/web/assets/javascripts/locales/jquery.timeago.en.js +0 -20
  152. data/web/assets/javascripts/locales/jquery.timeago.es.js +0 -18
  153. data/web/assets/javascripts/locales/jquery.timeago.et.js +0 -18
  154. data/web/assets/javascripts/locales/jquery.timeago.fa.js +0 -22
  155. data/web/assets/javascripts/locales/jquery.timeago.fi.js +0 -28
  156. data/web/assets/javascripts/locales/jquery.timeago.fr-short.js +0 -16
  157. data/web/assets/javascripts/locales/jquery.timeago.fr.js +0 -17
  158. data/web/assets/javascripts/locales/jquery.timeago.he.js +0 -18
  159. data/web/assets/javascripts/locales/jquery.timeago.hr.js +0 -49
  160. data/web/assets/javascripts/locales/jquery.timeago.hu.js +0 -18
  161. data/web/assets/javascripts/locales/jquery.timeago.hy.js +0 -18
  162. data/web/assets/javascripts/locales/jquery.timeago.id.js +0 -18
  163. data/web/assets/javascripts/locales/jquery.timeago.it.js +0 -16
  164. data/web/assets/javascripts/locales/jquery.timeago.ja.js +0 -19
  165. data/web/assets/javascripts/locales/jquery.timeago.ko.js +0 -17
  166. data/web/assets/javascripts/locales/jquery.timeago.lt.js +0 -20
  167. data/web/assets/javascripts/locales/jquery.timeago.mk.js +0 -20
  168. data/web/assets/javascripts/locales/jquery.timeago.nl.js +0 -20
  169. data/web/assets/javascripts/locales/jquery.timeago.no.js +0 -18
  170. data/web/assets/javascripts/locales/jquery.timeago.pl.js +0 -31
  171. data/web/assets/javascripts/locales/jquery.timeago.pt-br.js +0 -16
  172. data/web/assets/javascripts/locales/jquery.timeago.pt.js +0 -16
  173. data/web/assets/javascripts/locales/jquery.timeago.ro.js +0 -18
  174. data/web/assets/javascripts/locales/jquery.timeago.rs.js +0 -49
  175. data/web/assets/javascripts/locales/jquery.timeago.ru.js +0 -34
  176. data/web/assets/javascripts/locales/jquery.timeago.sk.js +0 -18
  177. data/web/assets/javascripts/locales/jquery.timeago.sl.js +0 -44
  178. data/web/assets/javascripts/locales/jquery.timeago.sv.js +0 -18
  179. data/web/assets/javascripts/locales/jquery.timeago.th.js +0 -20
  180. data/web/assets/javascripts/locales/jquery.timeago.tr.js +0 -16
  181. data/web/assets/javascripts/locales/jquery.timeago.uk.js +0 -34
  182. data/web/assets/javascripts/locales/jquery.timeago.uz.js +0 -19
  183. data/web/assets/javascripts/locales/jquery.timeago.zh-CN.js +0 -20
  184. data/web/assets/javascripts/locales/jquery.timeago.zh-TW.js +0 -20
  185. data/web/views/_poll.erb +0 -14
  186. data/web/views/_workers.erb +0 -29
  187. data/web/views/index.erb +0 -16
@@ -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
@@ -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