sidekiq 5.1.3 → 7.3.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (157) hide show
  1. checksums.yaml +5 -5
  2. data/Changes.md +756 -8
  3. data/LICENSE.txt +9 -0
  4. data/README.md +48 -51
  5. data/bin/multi_queue_bench +271 -0
  6. data/bin/sidekiq +22 -3
  7. data/bin/sidekiqload +213 -115
  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/{worker_spec.rb.erb → job_spec.rb.erb} +1 -1
  12. data/lib/generators/sidekiq/templates/{worker_test.rb.erb → job_test.rb.erb} +1 -1
  13. data/lib/sidekiq/api.rb +640 -330
  14. data/lib/sidekiq/capsule.rb +132 -0
  15. data/lib/sidekiq/cli.rb +244 -257
  16. data/lib/sidekiq/client.rb +132 -103
  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 +49 -12
  30. data/lib/sidekiq/job_retry.rb +167 -103
  31. data/lib/sidekiq/job_util.rb +109 -0
  32. data/lib/sidekiq/launcher.rb +209 -102
  33. data/lib/sidekiq/logger.rb +131 -0
  34. data/lib/sidekiq/manager.rb +43 -46
  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 +175 -112
  45. data/lib/sidekiq/rails.rb +54 -39
  46. data/lib/sidekiq/redis_client_adapter.rb +114 -0
  47. data/lib/sidekiq/redis_connection.rb +65 -86
  48. data/lib/sidekiq/ring_buffer.rb +31 -0
  49. data/lib/sidekiq/scheduled.rb +139 -48
  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 -94
  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 -12
  57. data/lib/sidekiq/web/application.rb +225 -76
  58. data/lib/sidekiq/web/csrf_protection.rb +183 -0
  59. data/lib/sidekiq/web/helpers.rb +215 -118
  60. data/lib/sidekiq/web/router.rb +23 -19
  61. data/lib/sidekiq/web.rb +114 -106
  62. data/lib/sidekiq/worker_compatibility_alias.rb +13 -0
  63. data/lib/sidekiq.rb +95 -182
  64. data/sidekiq.gemspec +26 -23
  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 +35 -283
  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 +10 -93
  75. data/web/assets/stylesheets/application.css +169 -522
  76. data/web/assets/stylesheets/bootstrap.css +2 -2
  77. data/web/locales/ar.yml +71 -64
  78. data/web/locales/cs.yml +62 -62
  79. data/web/locales/da.yml +60 -53
  80. data/web/locales/de.yml +65 -53
  81. data/web/locales/el.yml +43 -24
  82. data/web/locales/en.yml +86 -65
  83. data/web/locales/es.yml +70 -54
  84. data/web/locales/fa.yml +65 -65
  85. data/web/locales/fr.yml +83 -62
  86. data/web/locales/gd.yml +99 -0
  87. data/web/locales/he.yml +65 -64
  88. data/web/locales/hi.yml +59 -59
  89. data/web/locales/it.yml +53 -53
  90. data/web/locales/ja.yml +75 -64
  91. data/web/locales/ko.yml +52 -52
  92. data/web/locales/lt.yml +83 -0
  93. data/web/locales/nb.yml +61 -61
  94. data/web/locales/nl.yml +52 -52
  95. data/web/locales/pl.yml +45 -45
  96. data/web/locales/pt-br.yml +83 -55
  97. data/web/locales/pt.yml +51 -51
  98. data/web/locales/ru.yml +68 -63
  99. data/web/locales/sv.yml +53 -53
  100. data/web/locales/ta.yml +60 -60
  101. data/web/locales/tr.yml +101 -0
  102. data/web/locales/uk.yml +62 -61
  103. data/web/locales/ur.yml +64 -64
  104. data/web/locales/vi.yml +83 -0
  105. data/web/locales/zh-cn.yml +43 -16
  106. data/web/locales/zh-tw.yml +42 -8
  107. data/web/views/_footer.erb +18 -3
  108. data/web/views/_job_info.erb +21 -4
  109. data/web/views/_metrics_period_select.erb +12 -0
  110. data/web/views/_nav.erb +4 -18
  111. data/web/views/_paging.erb +2 -0
  112. data/web/views/_poll_link.erb +3 -6
  113. data/web/views/_summary.erb +7 -7
  114. data/web/views/busy.erb +79 -29
  115. data/web/views/dashboard.erb +49 -19
  116. data/web/views/dead.erb +3 -3
  117. data/web/views/filtering.erb +7 -0
  118. data/web/views/layout.erb +9 -7
  119. data/web/views/metrics.erb +91 -0
  120. data/web/views/metrics_for_job.erb +59 -0
  121. data/web/views/morgue.erb +14 -15
  122. data/web/views/queue.erb +33 -23
  123. data/web/views/queues.erb +19 -5
  124. data/web/views/retries.erb +19 -16
  125. data/web/views/retry.erb +3 -3
  126. data/web/views/scheduled.erb +17 -15
  127. metadata +84 -129
  128. data/.github/contributing.md +0 -32
  129. data/.github/issue_template.md +0 -11
  130. data/.gitignore +0 -13
  131. data/.travis.yml +0 -14
  132. data/3.0-Upgrade.md +0 -70
  133. data/4.0-Upgrade.md +0 -53
  134. data/5.0-Upgrade.md +0 -56
  135. data/COMM-LICENSE +0 -95
  136. data/Ent-Changes.md +0 -216
  137. data/Gemfile +0 -8
  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-4.0-Upgrade.md +0 -35
  142. data/Pro-Changes.md +0 -729
  143. data/Rakefile +0 -8
  144. data/bin/sidekiqctl +0 -99
  145. data/code_of_conduct.md +0 -50
  146. data/lib/generators/sidekiq/worker_generator.rb +0 -49
  147. data/lib/sidekiq/core_ext.rb +0 -1
  148. data/lib/sidekiq/delay.rb +0 -42
  149. data/lib/sidekiq/exception_handler.rb +0 -29
  150. data/lib/sidekiq/extensions/action_mailer.rb +0 -57
  151. data/lib/sidekiq/extensions/active_record.rb +0 -40
  152. data/lib/sidekiq/extensions/class_methods.rb +0 -40
  153. data/lib/sidekiq/extensions/generic_proxy.rb +0 -31
  154. data/lib/sidekiq/logging.rb +0 -122
  155. data/lib/sidekiq/middleware/server/active_record.rb +0 -23
  156. data/lib/sidekiq/util.rb +0 -66
  157. data/lib/sidekiq/worker.rb +0 -204
@@ -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,35 +54,26 @@ 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
58
-
59
- def constantize(str)
60
- names = str.split('::')
61
- names.shift if names.empty? || names.first.empty?
62
-
63
- names.inject(Object) do |constant, name|
64
- constant.const_defined?(name) ? constant.const_get(name) : constant.const_missing(name)
65
- end
66
- end
67
77
  end
68
78
  end
69
79
 
@@ -72,49 +82,49 @@ module Sidekiq
72
82
 
73
83
  class EmptyQueueError < RuntimeError; end
74
84
 
75
- class Client
76
- alias_method :raw_push_real, :raw_push
77
-
78
- def raw_push(payloads)
85
+ module TestingClient
86
+ def atomic_push(conn, payloads)
79
87
  if Sidekiq::Testing.fake?
80
88
  payloads.each do |job|
81
89
  job = Sidekiq.load_json(Sidekiq.dump_json(job))
82
- job.merge!('enqueued_at' => Time.now.to_f) unless job['at']
83
- 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)
84
92
  end
85
93
  true
86
94
  elsif Sidekiq::Testing.inline?
87
95
  payloads.each do |job|
88
- klass = Sidekiq::Testing.constantize(job['class'])
89
- job['id'] ||= SecureRandom.hex(12)
96
+ klass = Object.const_get(job["class"])
97
+ job["id"] ||= SecureRandom.hex(12)
90
98
  job_hash = Sidekiq.load_json(Sidekiq.dump_json(job))
91
99
  klass.process_job(job_hash)
92
100
  end
93
101
  true
94
102
  else
95
- raw_push_real(payloads)
103
+ super
96
104
  end
97
105
  end
98
106
  end
99
107
 
108
+ Sidekiq::Client.prepend TestingClient
109
+
100
110
  module Queues
101
111
  ##
102
112
  # The Queues class is only for testing the fake queue implementation.
103
113
  # There are 2 data structures involved in tandem. This is due to the
104
- # Rspec syntax of change(QueueWorker.jobs, :size). It keeps a reference
105
- # 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
106
116
  # jobs enqueued, it appeared as though the array didn't change.
107
117
  #
108
118
  # To solve this, we'll keep 2 hashes containing the jobs. One with keys based
109
- # on the queue, and another with keys of the worker names, so the array for
110
- # 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.
111
121
  #
112
122
  # Queue-based hash:
113
123
  #
114
124
  # {
115
125
  # "default"=>[
116
126
  # {
117
- # "class"=>"TestTesting::QueueWorker",
127
+ # "class"=>"TestTesting::HardJob",
118
128
  # "args"=>[1, 2],
119
129
  # "retry"=>true,
120
130
  # "queue"=>"default",
@@ -124,12 +134,12 @@ module Sidekiq
124
134
  # ]
125
135
  # }
126
136
  #
127
- # Worker-based hash:
137
+ # Job-based hash:
128
138
  #
129
139
  # {
130
- # "TestTesting::QueueWorker"=>[
140
+ # "TestTesting::HardJob"=>[
131
141
  # {
132
- # "class"=>"TestTesting::QueueWorker",
142
+ # "class"=>"TestTesting::HardJob",
133
143
  # "args"=>[1, 2],
134
144
  # "retry"=>true,
135
145
  # "queue"=>"default",
@@ -144,14 +154,14 @@ module Sidekiq
144
154
  # require 'sidekiq/testing'
145
155
  #
146
156
  # assert_equal 0, Sidekiq::Queues["default"].size
147
- # HardWorker.perform_async(:something)
157
+ # HardJob.perform_async(:something)
148
158
  # assert_equal 1, Sidekiq::Queues["default"].size
149
159
  # assert_equal :something, Sidekiq::Queues["default"].first['args'][0]
150
160
  #
151
- # You can also clear all workers' jobs:
161
+ # You can also clear all jobs:
152
162
  #
153
163
  # assert_equal 0, Sidekiq::Queues["default"].size
154
- # HardWorker.perform_async(:something)
164
+ # HardJob.perform_async(:something)
155
165
  # Sidekiq::Queues.clear_all
156
166
  # assert_equal 0, Sidekiq::Queues["default"].size
157
167
  #
@@ -170,35 +180,36 @@ module Sidekiq
170
180
 
171
181
  def push(queue, klass, job)
172
182
  jobs_by_queue[queue] << job
173
- jobs_by_worker[klass] << job
183
+ jobs_by_class[klass] << job
174
184
  end
175
185
 
176
186
  def jobs_by_queue
177
187
  @jobs_by_queue ||= Hash.new { |hash, key| hash[key] = [] }
178
188
  end
179
189
 
180
- def jobs_by_worker
181
- @jobs_by_worker ||= Hash.new { |hash, key| hash[key] = [] }
190
+ def jobs_by_class
191
+ @jobs_by_class ||= Hash.new { |hash, key| hash[key] = [] }
182
192
  end
193
+ alias_method :jobs_by_worker, :jobs_by_class
183
194
 
184
195
  def delete_for(jid, queue, klass)
185
196
  jobs_by_queue[queue.to_s].delete_if { |job| job["jid"] == jid }
186
- jobs_by_worker[klass].delete_if { |job| job["jid"] == jid }
197
+ jobs_by_class[klass].delete_if { |job| job["jid"] == jid }
187
198
  end
188
199
 
189
200
  def clear_for(queue, klass)
190
- jobs_by_queue[queue].clear
191
- jobs_by_worker[klass].clear
201
+ jobs_by_queue[queue.to_s].clear
202
+ jobs_by_class[klass].clear
192
203
  end
193
204
 
194
205
  def clear_all
195
206
  jobs_by_queue.clear
196
- jobs_by_worker.clear
207
+ jobs_by_class.clear
197
208
  end
198
209
  end
199
210
  end
200
211
 
201
- module Worker
212
+ module Job
202
213
  ##
203
214
  # The Sidekiq testing infrastructure overrides perform_async
204
215
  # so that it does not actually touch the network. Instead it
@@ -212,70 +223,53 @@ module Sidekiq
212
223
  #
213
224
  # require 'sidekiq/testing'
214
225
  #
215
- # assert_equal 0, HardWorker.jobs.size
216
- # HardWorker.perform_async(:something)
217
- # assert_equal 1, HardWorker.jobs.size
218
- # assert_equal :something, HardWorker.jobs[0]['args'][0]
219
- #
220
- # assert_equal 0, Sidekiq::Extensions::DelayedMailer.jobs.size
221
- # MyMailer.delay.send_welcome_email('foo@example.com')
222
- # assert_equal 1, Sidekiq::Extensions::DelayedMailer.jobs.size
223
- #
224
- # You can also clear and drain all workers' jobs:
225
- #
226
- # assert_equal 0, Sidekiq::Extensions::DelayedMailer.jobs.size
227
- # assert_equal 0, Sidekiq::Extensions::DelayedModel.jobs.size
228
- #
229
- # MyMailer.delay.send_welcome_email('foo@example.com')
230
- # MyModel.delay.do_something_hard
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]
231
230
  #
232
- # assert_equal 1, Sidekiq::Extensions::DelayedMailer.jobs.size
233
- # assert_equal 1, Sidekiq::Extensions::DelayedModel.jobs.size
231
+ # You can also clear and drain all job types:
234
232
  #
235
- # Sidekiq::Worker.clear_all # or .drain_all
236
- #
237
- # assert_equal 0, Sidekiq::Extensions::DelayedMailer.jobs.size
238
- # assert_equal 0, Sidekiq::Extensions::DelayedModel.jobs.size
233
+ # Sidekiq::Job.clear_all # or .drain_all
239
234
  #
240
235
  # This can be useful to make sure jobs don't linger between tests:
241
236
  #
242
237
  # RSpec.configure do |config|
243
238
  # config.before(:each) do
244
- # Sidekiq::Worker.clear_all
239
+ # Sidekiq::Job.clear_all
245
240
  # end
246
241
  # end
247
242
  #
248
243
  # or for acceptance testing, i.e. with cucumber:
249
244
  #
250
245
  # AfterStep do
251
- # Sidekiq::Worker.drain_all
246
+ # Sidekiq::Job.drain_all
252
247
  # end
253
248
  #
254
249
  # When I sign up as "foo@example.com"
255
250
  # Then I should receive a welcome email to "foo@example.com"
256
251
  #
257
252
  module ClassMethods
258
-
259
253
  # Queue for this worker
260
254
  def queue
261
- self.sidekiq_options["queue"]
255
+ get_sidekiq_options["queue"]
262
256
  end
263
257
 
264
258
  # Jobs queued for this worker
265
259
  def jobs
266
- Queues.jobs_by_worker[self.to_s]
260
+ Queues.jobs_by_class[to_s]
267
261
  end
268
262
 
269
263
  # Clear all jobs for this worker
270
264
  def clear
271
- Queues.clear_for(queue, self.to_s)
265
+ Queues.clear_for(queue, to_s)
272
266
  end
273
267
 
274
268
  # Drain and run all jobs for this worker
275
269
  def drain
276
270
  while jobs.any?
277
271
  next_job = jobs.first
278
- Queues.delete_for(next_job["jid"], next_job["queue"], self.to_s)
272
+ Queues.delete_for(next_job["jid"], next_job["queue"], to_s)
279
273
  process_job(next_job)
280
274
  end
281
275
  end
@@ -284,16 +278,16 @@ module Sidekiq
284
278
  def perform_one
285
279
  raise(EmptyQueueError, "perform_one called with empty job queue") if jobs.empty?
286
280
  next_job = jobs.first
287
- Queues.delete_for(next_job["jid"], queue, self.to_s)
281
+ Queues.delete_for(next_job["jid"], next_job["queue"], to_s)
288
282
  process_job(next_job)
289
283
  end
290
284
 
291
285
  def process_job(job)
292
- worker = new
293
- worker.jid = job['jid']
294
- worker.bid = job['bid'] if worker.respond_to?(:bid=)
295
- Sidekiq::Testing.server_middleware.invoke(worker, job, job['queue']) do
296
- 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"])
297
291
  end
298
292
  end
299
293
 
@@ -307,27 +301,34 @@ module Sidekiq
307
301
  Queues.jobs_by_queue.values.flatten
308
302
  end
309
303
 
310
- # Clear all queued jobs across all workers
304
+ # Clear all queued jobs
311
305
  def clear_all
312
306
  Queues.clear_all
313
307
  end
314
308
 
315
- # Drain all queued jobs across all workers
309
+ # Drain (execute) all queued jobs
316
310
  def drain_all
317
311
  while jobs.any?
318
- worker_classes = jobs.map { |job| job["class"] }.uniq
312
+ job_classes = jobs.map { |job| job["class"] }.uniq
319
313
 
320
- worker_classes.each do |worker_class|
321
- Sidekiq::Testing.constantize(worker_class).drain
314
+ job_classes.each do |job_class|
315
+ Object.const_get(job_class).drain
322
316
  end
323
317
  end
324
318
  end
325
319
  end
326
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
327
330
  end
328
331
 
329
- if defined?(::Rails) && Rails.respond_to?(:env) && !Rails.env.test?
330
- puts("**************************************************")
331
- puts("⛔️ WARNING: Sidekiq testing API enabled, but this is not the test environment. Your jobs will not go to Redis.")
332
- 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)
333
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 = "5.1.3"
4
+ VERSION = "7.3.1"
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'
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
@@ -40,10 +45,15 @@ module Sidekiq
40
45
  end
41
46
 
42
47
  def erb(content, options = {})
43
- if content.kind_of? Symbol
48
+ if content.is_a? Symbol
44
49
  unless respond_to?(:"_erb_#{content}")
45
- src = ERB.new(File.read("#{Web.settings.views}/#{content}.erb")).src
46
- 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
47
57
  end
48
58
  end
49
59
 
@@ -64,22 +74,22 @@ module Sidekiq
64
74
  end
65
75
 
66
76
  def json(payload)
67
- [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)]]
68
78
  end
69
79
 
70
80
  def initialize(env, block)
71
81
  @_erb = false
72
82
  @env = env
73
83
  @block = block
74
- @@files ||= {}
84
+ @files ||= {}
75
85
  end
76
86
 
77
87
  private
78
88
 
79
89
  def _erb(file, locals)
80
- locals.each {|k, v| define_singleton_method(k){ v } unless (singleton_methods.include? k)} if locals
90
+ locals&.each { |k, v| define_singleton_method(k) { v } unless singleton_methods.include? k }
81
91
 
82
- if file.kind_of?(String)
92
+ if file.is_a?(String)
83
93
  ERB.new(file).result(binding)
84
94
  else
85
95
  send(:"_erb_#{file}")