sidekiq 4.2.10 → 7.3.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (158) hide show
  1. checksums.yaml +5 -5
  2. data/Changes.md +859 -7
  3. data/LICENSE.txt +9 -0
  4. data/README.md +49 -50
  5. data/bin/multi_queue_bench +271 -0
  6. data/bin/sidekiq +22 -3
  7. data/bin/sidekiqload +212 -119
  8. data/bin/sidekiqmon +11 -0
  9. data/lib/generators/sidekiq/job_generator.rb +59 -0
  10. data/lib/generators/sidekiq/templates/{worker.rb.erb → job.rb.erb} +2 -2
  11. data/lib/generators/sidekiq/templates/job_spec.rb.erb +6 -0
  12. data/lib/generators/sidekiq/templates/{worker_test.rb.erb → job_test.rb.erb} +1 -1
  13. data/lib/sidekiq/api.rb +680 -315
  14. data/lib/sidekiq/capsule.rb +132 -0
  15. data/lib/sidekiq/cli.rb +268 -248
  16. data/lib/sidekiq/client.rb +136 -101
  17. data/lib/sidekiq/component.rb +68 -0
  18. data/lib/sidekiq/config.rb +293 -0
  19. data/lib/sidekiq/deploy.rb +64 -0
  20. data/lib/sidekiq/embedded.rb +63 -0
  21. data/lib/sidekiq/fetch.rb +49 -42
  22. data/lib/sidekiq/iterable_job.rb +55 -0
  23. data/lib/sidekiq/job/interrupt_handler.rb +24 -0
  24. data/lib/sidekiq/job/iterable/active_record_enumerator.rb +53 -0
  25. data/lib/sidekiq/job/iterable/csv_enumerator.rb +47 -0
  26. data/lib/sidekiq/job/iterable/enumerators.rb +135 -0
  27. data/lib/sidekiq/job/iterable.rb +231 -0
  28. data/lib/sidekiq/job.rb +385 -0
  29. data/lib/sidekiq/job_logger.rb +62 -0
  30. data/lib/sidekiq/job_retry.rb +305 -0
  31. data/lib/sidekiq/job_util.rb +109 -0
  32. data/lib/sidekiq/launcher.rb +208 -108
  33. data/lib/sidekiq/logger.rb +131 -0
  34. data/lib/sidekiq/manager.rb +43 -47
  35. data/lib/sidekiq/metrics/query.rb +158 -0
  36. data/lib/sidekiq/metrics/shared.rb +97 -0
  37. data/lib/sidekiq/metrics/tracking.rb +148 -0
  38. data/lib/sidekiq/middleware/chain.rb +113 -56
  39. data/lib/sidekiq/middleware/current_attributes.rb +113 -0
  40. data/lib/sidekiq/middleware/i18n.rb +7 -7
  41. data/lib/sidekiq/middleware/modules.rb +23 -0
  42. data/lib/sidekiq/monitor.rb +147 -0
  43. data/lib/sidekiq/paginator.rb +28 -16
  44. data/lib/sidekiq/processor.rb +188 -98
  45. data/lib/sidekiq/rails.rb +46 -97
  46. data/lib/sidekiq/redis_client_adapter.rb +114 -0
  47. data/lib/sidekiq/redis_connection.rb +71 -73
  48. data/lib/sidekiq/ring_buffer.rb +31 -0
  49. data/lib/sidekiq/scheduled.rb +140 -51
  50. data/lib/sidekiq/sd_notify.rb +149 -0
  51. data/lib/sidekiq/systemd.rb +26 -0
  52. data/lib/sidekiq/testing/inline.rb +6 -5
  53. data/lib/sidekiq/testing.rb +95 -85
  54. data/lib/sidekiq/transaction_aware_client.rb +51 -0
  55. data/lib/sidekiq/version.rb +3 -1
  56. data/lib/sidekiq/web/action.rb +22 -16
  57. data/lib/sidekiq/web/application.rb +230 -86
  58. data/lib/sidekiq/web/csrf_protection.rb +183 -0
  59. data/lib/sidekiq/web/helpers.rb +241 -104
  60. data/lib/sidekiq/web/router.rb +23 -19
  61. data/lib/sidekiq/web.rb +118 -110
  62. data/lib/sidekiq/worker_compatibility_alias.rb +13 -0
  63. data/lib/sidekiq.rb +96 -185
  64. data/sidekiq.gemspec +26 -27
  65. data/web/assets/images/apple-touch-icon.png +0 -0
  66. data/web/assets/javascripts/application.js +157 -61
  67. data/web/assets/javascripts/base-charts.js +106 -0
  68. data/web/assets/javascripts/chart.min.js +13 -0
  69. data/web/assets/javascripts/chartjs-plugin-annotation.min.js +7 -0
  70. data/web/assets/javascripts/dashboard-charts.js +192 -0
  71. data/web/assets/javascripts/dashboard.js +37 -280
  72. data/web/assets/javascripts/metrics.js +298 -0
  73. data/web/assets/stylesheets/application-dark.css +147 -0
  74. data/web/assets/stylesheets/application-rtl.css +163 -0
  75. data/web/assets/stylesheets/application.css +173 -198
  76. data/web/assets/stylesheets/bootstrap-rtl.min.css +9 -0
  77. data/web/assets/stylesheets/bootstrap.css +2 -2
  78. data/web/locales/ar.yml +87 -0
  79. data/web/locales/cs.yml +62 -62
  80. data/web/locales/da.yml +60 -53
  81. data/web/locales/de.yml +65 -53
  82. data/web/locales/el.yml +43 -24
  83. data/web/locales/en.yml +86 -64
  84. data/web/locales/es.yml +70 -53
  85. data/web/locales/fa.yml +65 -64
  86. data/web/locales/fr.yml +83 -62
  87. data/web/locales/gd.yml +99 -0
  88. data/web/locales/he.yml +80 -0
  89. data/web/locales/hi.yml +59 -59
  90. data/web/locales/it.yml +53 -53
  91. data/web/locales/ja.yml +75 -62
  92. data/web/locales/ko.yml +52 -52
  93. data/web/locales/lt.yml +83 -0
  94. data/web/locales/nb.yml +61 -61
  95. data/web/locales/nl.yml +52 -52
  96. data/web/locales/pl.yml +45 -45
  97. data/web/locales/pt-br.yml +83 -55
  98. data/web/locales/pt.yml +51 -51
  99. data/web/locales/ru.yml +68 -63
  100. data/web/locales/sv.yml +53 -53
  101. data/web/locales/ta.yml +60 -60
  102. data/web/locales/tr.yml +101 -0
  103. data/web/locales/uk.yml +62 -61
  104. data/web/locales/ur.yml +80 -0
  105. data/web/locales/vi.yml +83 -0
  106. data/web/locales/zh-cn.yml +43 -16
  107. data/web/locales/zh-tw.yml +42 -8
  108. data/web/views/_footer.erb +21 -3
  109. data/web/views/_job_info.erb +21 -4
  110. data/web/views/_metrics_period_select.erb +12 -0
  111. data/web/views/_nav.erb +5 -19
  112. data/web/views/_paging.erb +3 -1
  113. data/web/views/_poll_link.erb +3 -6
  114. data/web/views/_summary.erb +7 -7
  115. data/web/views/busy.erb +85 -31
  116. data/web/views/dashboard.erb +50 -20
  117. data/web/views/dead.erb +3 -3
  118. data/web/views/filtering.erb +7 -0
  119. data/web/views/layout.erb +17 -6
  120. data/web/views/metrics.erb +91 -0
  121. data/web/views/metrics_for_job.erb +59 -0
  122. data/web/views/morgue.erb +14 -15
  123. data/web/views/queue.erb +34 -24
  124. data/web/views/queues.erb +20 -4
  125. data/web/views/retries.erb +19 -16
  126. data/web/views/retry.erb +3 -3
  127. data/web/views/scheduled.erb +19 -17
  128. metadata +91 -198
  129. data/.github/contributing.md +0 -32
  130. data/.github/issue_template.md +0 -9
  131. data/.gitignore +0 -12
  132. data/.travis.yml +0 -18
  133. data/3.0-Upgrade.md +0 -70
  134. data/4.0-Upgrade.md +0 -53
  135. data/COMM-LICENSE +0 -95
  136. data/Ent-Changes.md +0 -173
  137. data/Gemfile +0 -29
  138. data/LICENSE +0 -9
  139. data/Pro-2.0-Upgrade.md +0 -138
  140. data/Pro-3.0-Upgrade.md +0 -44
  141. data/Pro-Changes.md +0 -628
  142. data/Rakefile +0 -12
  143. data/bin/sidekiqctl +0 -99
  144. data/code_of_conduct.md +0 -50
  145. data/lib/generators/sidekiq/templates/worker_spec.rb.erb +0 -6
  146. data/lib/generators/sidekiq/worker_generator.rb +0 -49
  147. data/lib/sidekiq/core_ext.rb +0 -119
  148. data/lib/sidekiq/exception_handler.rb +0 -31
  149. data/lib/sidekiq/extensions/action_mailer.rb +0 -57
  150. data/lib/sidekiq/extensions/active_record.rb +0 -40
  151. data/lib/sidekiq/extensions/class_methods.rb +0 -40
  152. data/lib/sidekiq/extensions/generic_proxy.rb +0 -25
  153. data/lib/sidekiq/logging.rb +0 -106
  154. data/lib/sidekiq/middleware/server/active_record.rb +0 -13
  155. data/lib/sidekiq/middleware/server/logging.rb +0 -31
  156. data/lib/sidekiq/middleware/server/retry_jobs.rb +0 -205
  157. data/lib/sidekiq/util.rb +0 -63
  158. data/lib/sidekiq/worker.rb +0 -121
@@ -1,9 +1,10 @@
1
1
  # frozen_string_literal: true
2
- require 'sidekiq/testing'
2
+
3
+ require "sidekiq/testing"
3
4
 
4
5
  ##
5
6
  # The Sidekiq inline infrastructure overrides perform_async so that it
6
- # actually calls perform instead. This allows workers to be run inline in a
7
+ # actually calls perform instead. This allows jobs to be run inline in a
7
8
  # testing environment.
8
9
  #
9
10
  # This is similar to `Resque.inline = true` functionality.
@@ -14,8 +15,8 @@ require 'sidekiq/testing'
14
15
  #
15
16
  # $external_variable = 0
16
17
  #
17
- # class ExternalWorker
18
- # include Sidekiq::Worker
18
+ # class ExternalJob
19
+ # include Sidekiq::Job
19
20
  #
20
21
  # def perform
21
22
  # $external_variable = 1
@@ -23,7 +24,7 @@ require 'sidekiq/testing'
23
24
  # end
24
25
  #
25
26
  # assert_equal 0, $external_variable
26
- # ExternalWorker.perform_async
27
+ # ExternalJob.perform_async
27
28
  # assert_equal 1, $external_variable
28
29
  #
29
30
  Sidekiq::Testing.inline!
@@ -1,27 +1,46 @@
1
1
  # frozen_string_literal: true
2
- require 'securerandom'
3
- require 'sidekiq'
4
2
 
5
- module Sidekiq
3
+ require "securerandom"
4
+ require "sidekiq"
6
5
 
6
+ module Sidekiq
7
7
  class Testing
8
+ class TestModeAlreadySetError < RuntimeError; end
8
9
  class << self
9
- attr_accessor :__test_mode
10
+ attr_accessor :__global_test_mode
10
11
 
12
+ # Calling without a block sets the global test mode, affecting
13
+ # all threads. Calling with a block only affects the current Thread.
11
14
  def __set_test_mode(mode)
12
15
  if block_given?
13
- current_mode = self.__test_mode
16
+ # Reentrant testing modes will lead to a rat's nest of code which is
17
+ # hard to reason about. You can set the testing mode once globally and
18
+ # you can override that global setting once per-thread.
19
+ raise TestModeAlreadySetError, "Nesting test modes is not supported" if __local_test_mode
20
+
21
+ self.__local_test_mode = mode
14
22
  begin
15
- self.__test_mode = mode
16
23
  yield
17
24
  ensure
18
- self.__test_mode = current_mode
25
+ self.__local_test_mode = nil
19
26
  end
20
27
  else
21
- self.__test_mode = mode
28
+ self.__global_test_mode = mode
22
29
  end
23
30
  end
24
31
 
32
+ def __test_mode
33
+ __local_test_mode || __global_test_mode
34
+ end
35
+
36
+ def __local_test_mode
37
+ Thread.current[:__sidekiq_test_mode]
38
+ end
39
+
40
+ def __local_test_mode=(value)
41
+ Thread.current[:__sidekiq_test_mode] = value
42
+ end
43
+
25
44
  def disable!(&block)
26
45
  __set_test_mode(:disable, &block)
27
46
  end
@@ -35,23 +54,23 @@ module Sidekiq
35
54
  end
36
55
 
37
56
  def enabled?
38
- self.__test_mode != :disable
57
+ __test_mode != :disable
39
58
  end
40
59
 
41
60
  def disabled?
42
- self.__test_mode == :disable
61
+ __test_mode == :disable
43
62
  end
44
63
 
45
64
  def fake?
46
- self.__test_mode == :fake
65
+ __test_mode == :fake
47
66
  end
48
67
 
49
68
  def inline?
50
- self.__test_mode == :inline
69
+ __test_mode == :inline
51
70
  end
52
71
 
53
72
  def server_middleware
54
- @server_chain ||= Middleware::Chain.new
73
+ @server_chain ||= Middleware::Chain.new(Sidekiq.default_configuration)
55
74
  yield @server_chain if block_given?
56
75
  @server_chain
57
76
  end
@@ -63,49 +82,49 @@ module Sidekiq
63
82
 
64
83
  class EmptyQueueError < RuntimeError; end
65
84
 
66
- class Client
67
- alias_method :raw_push_real, :raw_push
68
-
69
- def raw_push(payloads)
85
+ module TestingClient
86
+ def atomic_push(conn, payloads)
70
87
  if Sidekiq::Testing.fake?
71
88
  payloads.each do |job|
72
89
  job = Sidekiq.load_json(Sidekiq.dump_json(job))
73
- job.merge!('enqueued_at' => Time.now.to_f) unless job['at']
74
- Queues.push(job['queue'], job['class'], job)
90
+ job["enqueued_at"] = Time.now.to_f unless job["at"]
91
+ Queues.push(job["queue"], job["class"], job)
75
92
  end
76
93
  true
77
94
  elsif Sidekiq::Testing.inline?
78
95
  payloads.each do |job|
79
- klass = job['class'].constantize
80
- job['id'] ||= SecureRandom.hex(12)
96
+ klass = Object.const_get(job["class"])
97
+ job["id"] ||= SecureRandom.hex(12)
81
98
  job_hash = Sidekiq.load_json(Sidekiq.dump_json(job))
82
99
  klass.process_job(job_hash)
83
100
  end
84
101
  true
85
102
  else
86
- raw_push_real(payloads)
103
+ super
87
104
  end
88
105
  end
89
106
  end
90
107
 
108
+ Sidekiq::Client.prepend TestingClient
109
+
91
110
  module Queues
92
111
  ##
93
112
  # The Queues class is only for testing the fake queue implementation.
94
113
  # There are 2 data structures involved in tandem. This is due to the
95
- # Rspec syntax of change(QueueWorker.jobs, :size). It keeps a reference
96
- # to the array. Because the array was dervied from a filter of the total
114
+ # Rspec syntax of change(HardJob.jobs, :size). It keeps a reference
115
+ # to the array. Because the array was derived from a filter of the total
97
116
  # jobs enqueued, it appeared as though the array didn't change.
98
117
  #
99
118
  # To solve this, we'll keep 2 hashes containing the jobs. One with keys based
100
- # on the queue, and another with keys of the worker names, so the array for
101
- # QueueWorker.jobs is a straight reference to a real array.
119
+ # on the queue, and another with keys of the job type, so the array for
120
+ # HardJob.jobs is a straight reference to a real array.
102
121
  #
103
122
  # Queue-based hash:
104
123
  #
105
124
  # {
106
125
  # "default"=>[
107
126
  # {
108
- # "class"=>"TestTesting::QueueWorker",
127
+ # "class"=>"TestTesting::HardJob",
109
128
  # "args"=>[1, 2],
110
129
  # "retry"=>true,
111
130
  # "queue"=>"default",
@@ -115,12 +134,12 @@ module Sidekiq
115
134
  # ]
116
135
  # }
117
136
  #
118
- # Worker-based hash:
137
+ # Job-based hash:
119
138
  #
120
139
  # {
121
- # "TestTesting::QueueWorker"=>[
140
+ # "TestTesting::HardJob"=>[
122
141
  # {
123
- # "class"=>"TestTesting::QueueWorker",
142
+ # "class"=>"TestTesting::HardJob",
124
143
  # "args"=>[1, 2],
125
144
  # "retry"=>true,
126
145
  # "queue"=>"default",
@@ -135,14 +154,14 @@ module Sidekiq
135
154
  # require 'sidekiq/testing'
136
155
  #
137
156
  # assert_equal 0, Sidekiq::Queues["default"].size
138
- # HardWorker.perform_async(:something)
157
+ # HardJob.perform_async(:something)
139
158
  # assert_equal 1, Sidekiq::Queues["default"].size
140
159
  # assert_equal :something, Sidekiq::Queues["default"].first['args'][0]
141
160
  #
142
- # You can also clear all workers' jobs:
161
+ # You can also clear all jobs:
143
162
  #
144
163
  # assert_equal 0, Sidekiq::Queues["default"].size
145
- # HardWorker.perform_async(:something)
164
+ # HardJob.perform_async(:something)
146
165
  # Sidekiq::Queues.clear_all
147
166
  # assert_equal 0, Sidekiq::Queues["default"].size
148
167
  #
@@ -161,35 +180,36 @@ module Sidekiq
161
180
 
162
181
  def push(queue, klass, job)
163
182
  jobs_by_queue[queue] << job
164
- jobs_by_worker[klass] << job
183
+ jobs_by_class[klass] << job
165
184
  end
166
185
 
167
186
  def jobs_by_queue
168
187
  @jobs_by_queue ||= Hash.new { |hash, key| hash[key] = [] }
169
188
  end
170
189
 
171
- def jobs_by_worker
172
- @jobs_by_worker ||= Hash.new { |hash, key| hash[key] = [] }
190
+ def jobs_by_class
191
+ @jobs_by_class ||= Hash.new { |hash, key| hash[key] = [] }
173
192
  end
193
+ alias_method :jobs_by_worker, :jobs_by_class
174
194
 
175
195
  def delete_for(jid, queue, klass)
176
196
  jobs_by_queue[queue.to_s].delete_if { |job| job["jid"] == jid }
177
- jobs_by_worker[klass].delete_if { |job| job["jid"] == jid }
197
+ jobs_by_class[klass].delete_if { |job| job["jid"] == jid }
178
198
  end
179
199
 
180
200
  def clear_for(queue, klass)
181
- jobs_by_queue[queue].clear
182
- jobs_by_worker[klass].clear
201
+ jobs_by_queue[queue.to_s].clear
202
+ jobs_by_class[klass].clear
183
203
  end
184
204
 
185
205
  def clear_all
186
206
  jobs_by_queue.clear
187
- jobs_by_worker.clear
207
+ jobs_by_class.clear
188
208
  end
189
209
  end
190
210
  end
191
211
 
192
- module Worker
212
+ module Job
193
213
  ##
194
214
  # The Sidekiq testing infrastructure overrides perform_async
195
215
  # so that it does not actually touch the network. Instead it
@@ -203,70 +223,53 @@ module Sidekiq
203
223
  #
204
224
  # require 'sidekiq/testing'
205
225
  #
206
- # assert_equal 0, HardWorker.jobs.size
207
- # HardWorker.perform_async(:something)
208
- # assert_equal 1, HardWorker.jobs.size
209
- # assert_equal :something, HardWorker.jobs[0]['args'][0]
226
+ # assert_equal 0, HardJob.jobs.size
227
+ # HardJob.perform_async(:something)
228
+ # assert_equal 1, HardJob.jobs.size
229
+ # assert_equal :something, HardJob.jobs[0]['args'][0]
210
230
  #
211
- # assert_equal 0, Sidekiq::Extensions::DelayedMailer.jobs.size
212
- # MyMailer.delay.send_welcome_email('foo@example.com')
213
- # assert_equal 1, Sidekiq::Extensions::DelayedMailer.jobs.size
231
+ # You can also clear and drain all job types:
214
232
  #
215
- # You can also clear and drain all workers' jobs:
216
- #
217
- # assert_equal 0, Sidekiq::Extensions::DelayedMailer.jobs.size
218
- # assert_equal 0, Sidekiq::Extensions::DelayedModel.jobs.size
219
- #
220
- # MyMailer.delay.send_welcome_email('foo@example.com')
221
- # MyModel.delay.do_something_hard
222
- #
223
- # assert_equal 1, Sidekiq::Extensions::DelayedMailer.jobs.size
224
- # assert_equal 1, Sidekiq::Extensions::DelayedModel.jobs.size
225
- #
226
- # Sidekiq::Worker.clear_all # or .drain_all
227
- #
228
- # assert_equal 0, Sidekiq::Extensions::DelayedMailer.jobs.size
229
- # assert_equal 0, Sidekiq::Extensions::DelayedModel.jobs.size
233
+ # Sidekiq::Job.clear_all # or .drain_all
230
234
  #
231
235
  # This can be useful to make sure jobs don't linger between tests:
232
236
  #
233
237
  # RSpec.configure do |config|
234
238
  # config.before(:each) do
235
- # Sidekiq::Worker.clear_all
239
+ # Sidekiq::Job.clear_all
236
240
  # end
237
241
  # end
238
242
  #
239
243
  # or for acceptance testing, i.e. with cucumber:
240
244
  #
241
245
  # AfterStep do
242
- # Sidekiq::Worker.drain_all
246
+ # Sidekiq::Job.drain_all
243
247
  # end
244
248
  #
245
249
  # When I sign up as "foo@example.com"
246
250
  # Then I should receive a welcome email to "foo@example.com"
247
251
  #
248
252
  module ClassMethods
249
-
250
253
  # Queue for this worker
251
254
  def queue
252
- self.sidekiq_options["queue"]
255
+ get_sidekiq_options["queue"]
253
256
  end
254
257
 
255
258
  # Jobs queued for this worker
256
259
  def jobs
257
- Queues.jobs_by_worker[self.to_s]
260
+ Queues.jobs_by_class[to_s]
258
261
  end
259
262
 
260
263
  # Clear all jobs for this worker
261
264
  def clear
262
- Queues.clear_for(queue, self.to_s)
265
+ Queues.clear_for(queue, to_s)
263
266
  end
264
267
 
265
268
  # Drain and run all jobs for this worker
266
269
  def drain
267
270
  while jobs.any?
268
271
  next_job = jobs.first
269
- Queues.delete_for(next_job["jid"], next_job["queue"], self.to_s)
272
+ Queues.delete_for(next_job["jid"], next_job["queue"], to_s)
270
273
  process_job(next_job)
271
274
  end
272
275
  end
@@ -275,16 +278,16 @@ module Sidekiq
275
278
  def perform_one
276
279
  raise(EmptyQueueError, "perform_one called with empty job queue") if jobs.empty?
277
280
  next_job = jobs.first
278
- Queues.delete_for(next_job["jid"], queue, self.to_s)
281
+ Queues.delete_for(next_job["jid"], next_job["queue"], to_s)
279
282
  process_job(next_job)
280
283
  end
281
284
 
282
285
  def process_job(job)
283
- worker = new
284
- worker.jid = job['jid']
285
- worker.bid = job['bid'] if worker.respond_to?(:bid=)
286
- Sidekiq::Testing.server_middleware.invoke(worker, job, job['queue']) do
287
- execute_job(worker, job['args'])
286
+ inst = new
287
+ inst.jid = job["jid"]
288
+ inst.bid = job["bid"] if inst.respond_to?(:bid=)
289
+ Sidekiq::Testing.server_middleware.invoke(inst, job, job["queue"]) do
290
+ execute_job(inst, job["args"])
288
291
  end
289
292
  end
290
293
 
@@ -298,27 +301,34 @@ module Sidekiq
298
301
  Queues.jobs_by_queue.values.flatten
299
302
  end
300
303
 
301
- # Clear all queued jobs across all workers
304
+ # Clear all queued jobs
302
305
  def clear_all
303
306
  Queues.clear_all
304
307
  end
305
308
 
306
- # Drain all queued jobs across all workers
309
+ # Drain (execute) all queued jobs
307
310
  def drain_all
308
311
  while jobs.any?
309
- worker_classes = jobs.map { |job| job["class"] }.uniq
312
+ job_classes = jobs.map { |job| job["class"] }.uniq
310
313
 
311
- worker_classes.each do |worker_class|
312
- worker_class.constantize.drain
314
+ job_classes.each do |job_class|
315
+ Object.const_get(job_class).drain
313
316
  end
314
317
  end
315
318
  end
316
319
  end
317
320
  end
321
+
322
+ module TestingExtensions
323
+ def jobs_for(klass)
324
+ jobs.select do |job|
325
+ marshalled = job["args"][0]
326
+ marshalled.index(klass.to_s) && YAML.safe_load(marshalled)[0] == klass
327
+ end
328
+ end
329
+ end
318
330
  end
319
331
 
320
- if defined?(::Rails) && !Rails.env.test?
321
- puts("**************************************************")
322
- puts("⛔️ WARNING: Sidekiq testing API enabled, but this is not the test environment. Your jobs will not go to Redis.")
323
- puts("**************************************************")
332
+ if defined?(::Rails) && Rails.respond_to?(:env) && !Rails.env.test? && !$TESTING
333
+ warn("⛔️ WARNING: Sidekiq testing API enabled, but this is not the test environment. Your jobs will not go to Redis.", uplevel: 1)
324
334
  end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "securerandom"
4
+ require "sidekiq/client"
5
+
6
+ module Sidekiq
7
+ class TransactionAwareClient
8
+ def initialize(pool: nil, config: nil)
9
+ @redis_client = Client.new(pool: pool, config: config)
10
+ end
11
+
12
+ def batching?
13
+ Thread.current[:sidekiq_batch]
14
+ end
15
+
16
+ def push(item)
17
+ # 6160 we can't support both Sidekiq::Batch and transactions.
18
+ return @redis_client.push(item) if batching?
19
+
20
+ # pre-allocate the JID so we can return it immediately and
21
+ # save it to the database as part of the transaction.
22
+ item["jid"] ||= SecureRandom.hex(12)
23
+ AfterCommitEverywhere.after_commit { @redis_client.push(item) }
24
+ item["jid"]
25
+ end
26
+
27
+ ##
28
+ # We don't provide transactionality for push_bulk because we don't want
29
+ # to hold potentially hundreds of thousands of job records in memory due to
30
+ # a long running enqueue process.
31
+ def push_bulk(items)
32
+ @redis_client.push_bulk(items)
33
+ end
34
+ end
35
+ end
36
+
37
+ ##
38
+ # Use `Sidekiq.transactional_push!` in your sidekiq.rb initializer
39
+ module Sidekiq
40
+ def self.transactional_push!
41
+ begin
42
+ require "after_commit_everywhere"
43
+ rescue LoadError
44
+ raise %q(You need to add `gem "after_commit_everywhere"` to your Gemfile to use Sidekiq's transactional client)
45
+ end
46
+
47
+ Sidekiq.default_job_options["client_class"] = Sidekiq::TransactionAwareClient
48
+ Sidekiq::JobUtil::TRANSIENT_ATTRIBUTES << "client_class"
49
+ true
50
+ end
51
+ end
@@ -1,4 +1,6 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Sidekiq
3
- VERSION = "4.2.10"
4
+ VERSION = "7.3.2"
5
+ MAJOR = 7
4
6
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Sidekiq
4
4
  class WebAction
5
- RACK_SESSION = 'rack.session'.freeze
5
+ RACK_SESSION = "rack.session"
6
6
 
7
7
  attr_accessor :env, :block, :type
8
8
 
@@ -15,18 +15,23 @@ module Sidekiq
15
15
  end
16
16
 
17
17
  def halt(res)
18
- throw :halt, res
18
+ throw :halt, [res, {Rack::CONTENT_TYPE => "text/plain"}, [res.to_s]]
19
19
  end
20
20
 
21
21
  def redirect(location)
22
- throw :halt, [302, { "Location" => "#{request.base_url}#{location}" }, []]
22
+ throw :halt, [302, {Web::LOCATION => "#{request.base_url}#{location}"}, []]
23
+ end
24
+
25
+ def reload_page
26
+ current_location = request.referer.gsub(request.base_url, "")
27
+ redirect current_location
23
28
  end
24
29
 
25
30
  def params
26
- indifferent_hash = Hash.new {|hash,key| hash[key.to_s] if Symbol === key }
31
+ indifferent_hash = Hash.new { |hash, key| hash[key.to_s] if Symbol === key }
27
32
 
28
33
  indifferent_hash.merge! request.params
29
- route_params.each {|k,v| indifferent_hash[k.to_s] = v }
34
+ route_params.each { |k, v| indifferent_hash[k.to_s] = v }
30
35
 
31
36
  indifferent_hash
32
37
  end
@@ -39,15 +44,16 @@ module Sidekiq
39
44
  env[RACK_SESSION]
40
45
  end
41
46
 
42
- def content_type(type)
43
- @type = type
44
- end
45
-
46
47
  def erb(content, options = {})
47
- if content.kind_of? Symbol
48
+ if content.is_a? Symbol
48
49
  unless respond_to?(:"_erb_#{content}")
49
- src = ERB.new(File.read("#{Web.settings.views}/#{content}.erb")).src
50
- WebAction.class_eval("def _erb_#{content}\n#{src}\n end")
50
+ views = options[:views] || Web.settings.views
51
+ src = ERB.new(File.read("#{views}/#{content}.erb")).src
52
+ WebAction.class_eval <<-RUBY, __FILE__, __LINE__ + 1
53
+ def _erb_#{content}
54
+ #{src}
55
+ end
56
+ RUBY
51
57
  end
52
58
  end
53
59
 
@@ -68,22 +74,22 @@ module Sidekiq
68
74
  end
69
75
 
70
76
  def json(payload)
71
- [200, { "Content-Type" => "application/json", "Cache-Control" => "no-cache" }, [Sidekiq.dump_json(payload)]]
77
+ [200, {Rack::CONTENT_TYPE => "application/json", Rack::CACHE_CONTROL => "private, no-store"}, [Sidekiq.dump_json(payload)]]
72
78
  end
73
79
 
74
80
  def initialize(env, block)
75
81
  @_erb = false
76
82
  @env = env
77
83
  @block = block
78
- @@files ||= {}
84
+ @files ||= {}
79
85
  end
80
86
 
81
87
  private
82
88
 
83
89
  def _erb(file, locals)
84
- locals.each {|k, v| define_singleton_method(k){ v } } if locals
90
+ locals&.each { |k, v| define_singleton_method(k) { v } unless singleton_methods.include? k }
85
91
 
86
- if file.kind_of?(String)
92
+ if file.is_a?(String)
87
93
  ERB.new(file).result(binding)
88
94
  else
89
95
  send(:"_erb_#{file}")