sidekiq 4.2.10 → 7.3.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (159) hide show
  1. checksums.yaml +5 -5
  2. data/Changes.md +932 -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 +218 -116
  8. data/bin/sidekiqmon +11 -0
  9. data/lib/active_job/queue_adapters/sidekiq_adapter.rb +75 -0
  10. data/lib/generators/sidekiq/job_generator.rb +59 -0
  11. data/lib/generators/sidekiq/templates/{worker.rb.erb → job.rb.erb} +2 -2
  12. data/lib/generators/sidekiq/templates/job_spec.rb.erb +6 -0
  13. data/lib/generators/sidekiq/templates/{worker_test.rb.erb → job_test.rb.erb} +1 -1
  14. data/lib/sidekiq/api.rb +710 -322
  15. data/lib/sidekiq/capsule.rb +132 -0
  16. data/lib/sidekiq/cli.rb +268 -248
  17. data/lib/sidekiq/client.rb +153 -101
  18. data/lib/sidekiq/component.rb +90 -0
  19. data/lib/sidekiq/config.rb +311 -0
  20. data/lib/sidekiq/deploy.rb +64 -0
  21. data/lib/sidekiq/embedded.rb +63 -0
  22. data/lib/sidekiq/fetch.rb +50 -42
  23. data/lib/sidekiq/iterable_job.rb +55 -0
  24. data/lib/sidekiq/job/interrupt_handler.rb +24 -0
  25. data/lib/sidekiq/job/iterable/active_record_enumerator.rb +53 -0
  26. data/lib/sidekiq/job/iterable/csv_enumerator.rb +47 -0
  27. data/lib/sidekiq/job/iterable/enumerators.rb +135 -0
  28. data/lib/sidekiq/job/iterable.rb +294 -0
  29. data/lib/sidekiq/job.rb +385 -0
  30. data/lib/sidekiq/job_logger.rb +52 -0
  31. data/lib/sidekiq/job_retry.rb +305 -0
  32. data/lib/sidekiq/job_util.rb +109 -0
  33. data/lib/sidekiq/launcher.rb +208 -108
  34. data/lib/sidekiq/logger.rb +131 -0
  35. data/lib/sidekiq/manager.rb +43 -47
  36. data/lib/sidekiq/metrics/query.rb +158 -0
  37. data/lib/sidekiq/metrics/shared.rb +106 -0
  38. data/lib/sidekiq/metrics/tracking.rb +148 -0
  39. data/lib/sidekiq/middleware/chain.rb +113 -56
  40. data/lib/sidekiq/middleware/current_attributes.rb +128 -0
  41. data/lib/sidekiq/middleware/i18n.rb +9 -7
  42. data/lib/sidekiq/middleware/modules.rb +23 -0
  43. data/lib/sidekiq/monitor.rb +147 -0
  44. data/lib/sidekiq/paginator.rb +33 -15
  45. data/lib/sidekiq/processor.rb +188 -98
  46. data/lib/sidekiq/rails.rb +53 -92
  47. data/lib/sidekiq/redis_client_adapter.rb +114 -0
  48. data/lib/sidekiq/redis_connection.rb +86 -77
  49. data/lib/sidekiq/ring_buffer.rb +32 -0
  50. data/lib/sidekiq/scheduled.rb +140 -51
  51. data/lib/sidekiq/sd_notify.rb +149 -0
  52. data/lib/sidekiq/systemd.rb +26 -0
  53. data/lib/sidekiq/testing/inline.rb +6 -5
  54. data/lib/sidekiq/testing.rb +95 -85
  55. data/lib/sidekiq/transaction_aware_client.rb +59 -0
  56. data/lib/sidekiq/version.rb +7 -1
  57. data/lib/sidekiq/web/action.rb +40 -18
  58. data/lib/sidekiq/web/application.rb +189 -89
  59. data/lib/sidekiq/web/csrf_protection.rb +183 -0
  60. data/lib/sidekiq/web/helpers.rb +239 -101
  61. data/lib/sidekiq/web/router.rb +28 -21
  62. data/lib/sidekiq/web.rb +123 -110
  63. data/lib/sidekiq/worker_compatibility_alias.rb +13 -0
  64. data/lib/sidekiq.rb +97 -185
  65. data/sidekiq.gemspec +26 -27
  66. data/web/assets/images/apple-touch-icon.png +0 -0
  67. data/web/assets/javascripts/application.js +157 -61
  68. data/web/assets/javascripts/base-charts.js +106 -0
  69. data/web/assets/javascripts/chart.min.js +13 -0
  70. data/web/assets/javascripts/chartjs-plugin-annotation.min.js +7 -0
  71. data/web/assets/javascripts/dashboard-charts.js +194 -0
  72. data/web/assets/javascripts/dashboard.js +43 -280
  73. data/web/assets/javascripts/metrics.js +298 -0
  74. data/web/assets/stylesheets/application-dark.css +147 -0
  75. data/web/assets/stylesheets/application-rtl.css +163 -0
  76. data/web/assets/stylesheets/application.css +176 -196
  77. data/web/assets/stylesheets/bootstrap-rtl.min.css +9 -0
  78. data/web/assets/stylesheets/bootstrap.css +2 -2
  79. data/web/locales/ar.yml +87 -0
  80. data/web/locales/cs.yml +62 -62
  81. data/web/locales/da.yml +60 -53
  82. data/web/locales/de.yml +65 -53
  83. data/web/locales/el.yml +43 -24
  84. data/web/locales/en.yml +88 -64
  85. data/web/locales/es.yml +70 -53
  86. data/web/locales/fa.yml +65 -64
  87. data/web/locales/fr.yml +82 -62
  88. data/web/locales/gd.yml +98 -0
  89. data/web/locales/he.yml +80 -0
  90. data/web/locales/hi.yml +59 -59
  91. data/web/locales/it.yml +85 -54
  92. data/web/locales/ja.yml +74 -62
  93. data/web/locales/ko.yml +52 -52
  94. data/web/locales/lt.yml +83 -0
  95. data/web/locales/nb.yml +61 -61
  96. data/web/locales/nl.yml +52 -52
  97. data/web/locales/pl.yml +45 -45
  98. data/web/locales/pt-br.yml +82 -55
  99. data/web/locales/pt.yml +51 -51
  100. data/web/locales/ru.yml +68 -63
  101. data/web/locales/sv.yml +53 -53
  102. data/web/locales/ta.yml +60 -60
  103. data/web/locales/tr.yml +100 -0
  104. data/web/locales/uk.yml +85 -61
  105. data/web/locales/ur.yml +80 -0
  106. data/web/locales/vi.yml +83 -0
  107. data/web/locales/zh-cn.yml +42 -16
  108. data/web/locales/zh-tw.yml +41 -8
  109. data/web/views/_footer.erb +20 -3
  110. data/web/views/_job_info.erb +21 -4
  111. data/web/views/_metrics_period_select.erb +12 -0
  112. data/web/views/_nav.erb +5 -19
  113. data/web/views/_paging.erb +3 -1
  114. data/web/views/_poll_link.erb +3 -6
  115. data/web/views/_summary.erb +7 -7
  116. data/web/views/busy.erb +85 -31
  117. data/web/views/dashboard.erb +53 -20
  118. data/web/views/dead.erb +3 -3
  119. data/web/views/filtering.erb +6 -0
  120. data/web/views/layout.erb +17 -6
  121. data/web/views/metrics.erb +90 -0
  122. data/web/views/metrics_for_job.erb +59 -0
  123. data/web/views/morgue.erb +15 -16
  124. data/web/views/queue.erb +35 -25
  125. data/web/views/queues.erb +20 -4
  126. data/web/views/retries.erb +19 -16
  127. data/web/views/retry.erb +3 -3
  128. data/web/views/scheduled.erb +19 -17
  129. metadata +103 -194
  130. data/.github/contributing.md +0 -32
  131. data/.github/issue_template.md +0 -9
  132. data/.gitignore +0 -12
  133. data/.travis.yml +0 -18
  134. data/3.0-Upgrade.md +0 -70
  135. data/4.0-Upgrade.md +0 -53
  136. data/COMM-LICENSE +0 -95
  137. data/Ent-Changes.md +0 -173
  138. data/Gemfile +0 -29
  139. data/LICENSE +0 -9
  140. data/Pro-2.0-Upgrade.md +0 -138
  141. data/Pro-3.0-Upgrade.md +0 -44
  142. data/Pro-Changes.md +0 -628
  143. data/Rakefile +0 -12
  144. data/bin/sidekiqctl +0 -99
  145. data/code_of_conduct.md +0 -50
  146. data/lib/generators/sidekiq/templates/worker_spec.rb.erb +0 -6
  147. data/lib/generators/sidekiq/worker_generator.rb +0 -49
  148. data/lib/sidekiq/core_ext.rb +0 -119
  149. data/lib/sidekiq/exception_handler.rb +0 -31
  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 -25
  154. data/lib/sidekiq/logging.rb +0 -106
  155. data/lib/sidekiq/middleware/server/active_record.rb +0 -13
  156. data/lib/sidekiq/middleware/server/logging.rb +0 -31
  157. data/lib/sidekiq/middleware/server/retry_jobs.rb +0 -205
  158. data/lib/sidekiq/util.rb +0 -63
  159. 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
+ instance = new
287
+ instance.jid = job["jid"]
288
+ instance.bid = job["bid"] if instance.respond_to?(:bid=)
289
+ Sidekiq::Testing.server_middleware.invoke(instance, job, job["queue"]) do
290
+ execute_job(instance, 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,59 @@
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
+ @transaction_backend =
11
+ if ActiveRecord.version >= Gem::Version.new("7.2")
12
+ ActiveRecord.method(:after_all_transactions_commit)
13
+ else
14
+ AfterCommitEverywhere.method(:after_commit)
15
+ end
16
+ end
17
+
18
+ def batching?
19
+ Thread.current[:sidekiq_batch]
20
+ end
21
+
22
+ def push(item)
23
+ # 6160 we can't support both Sidekiq::Batch and transactions.
24
+ return @redis_client.push(item) if batching?
25
+
26
+ # pre-allocate the JID so we can return it immediately and
27
+ # save it to the database as part of the transaction.
28
+ item["jid"] ||= SecureRandom.hex(12)
29
+ @transaction_backend.call { @redis_client.push(item) }
30
+ item["jid"]
31
+ end
32
+
33
+ ##
34
+ # We don't provide transactionality for push_bulk because we don't want
35
+ # to hold potentially hundreds of thousands of job records in memory due to
36
+ # a long running enqueue process.
37
+ def push_bulk(items)
38
+ @redis_client.push_bulk(items)
39
+ end
40
+ end
41
+ end
42
+
43
+ ##
44
+ # Use `Sidekiq.transactional_push!` in your sidekiq.rb initializer
45
+ module Sidekiq
46
+ def self.transactional_push!
47
+ if ActiveRecord.version < Gem::Version.new("7.2")
48
+ begin
49
+ require "after_commit_everywhere"
50
+ rescue LoadError
51
+ raise %q(You need ActiveRecord >= 7.2 or to add `gem "after_commit_everywhere"` to your Gemfile to use Sidekiq's transactional client)
52
+ end
53
+ end
54
+
55
+ Sidekiq.default_job_options["client_class"] = Sidekiq::TransactionAwareClient
56
+ Sidekiq::JobUtil::TRANSIENT_ATTRIBUTES << "client_class"
57
+ true
58
+ end
59
+ end
@@ -1,4 +1,10 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Sidekiq
3
- VERSION = "4.2.10"
4
+ VERSION = "7.3.10"
5
+ MAJOR = 7
6
+
7
+ def self.gem_version
8
+ Gem::Version.new(VERSION)
9
+ end
4
10
  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,39 +15,61 @@ 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
23
  end
24
24
 
25
+ def reload_page
26
+ current_location = request.referer.gsub(request.base_url, "")
27
+ redirect current_location
28
+ end
29
+
30
+ # deprecated, will warn in 8.0
25
31
  def params
26
- indifferent_hash = Hash.new {|hash,key| hash[key.to_s] if Symbol === key }
32
+ indifferent_hash = Hash.new { |hash, key| hash[key.to_s] if Symbol === key }
27
33
 
28
34
  indifferent_hash.merge! request.params
29
- route_params.each {|k,v| indifferent_hash[k.to_s] = v }
35
+ route_params.each { |k, v| indifferent_hash[k.to_s] = v }
30
36
 
31
37
  indifferent_hash
32
38
  end
33
39
 
34
- def route_params
35
- env[WebRouter::ROUTE_PARAMS]
40
+ # Use like `url_params("page")` within your action blocks
41
+ def url_params(key)
42
+ request.params[key]
36
43
  end
37
44
 
38
- def session
39
- env[RACK_SESSION]
45
+ # Use like `route_params(:name)` within your action blocks
46
+ # key is required in 8.0, nil is only used for backwards compatibility
47
+ def route_params(key = nil)
48
+ if key
49
+ env[WebRouter::ROUTE_PARAMS][key]
50
+ else
51
+ env[WebRouter::ROUTE_PARAMS]
52
+ end
40
53
  end
41
54
 
42
- def content_type(type)
43
- @type = type
55
+ def session
56
+ env[RACK_SESSION]
44
57
  end
45
58
 
46
59
  def erb(content, options = {})
47
- if content.kind_of? Symbol
60
+ if content.is_a? Symbol
48
61
  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")
62
+ views = options[:views] || Web.settings.views
63
+ filename = "#{views}/#{content}.erb"
64
+ src = ERB.new(File.read(filename)).src
65
+
66
+ # Need to use lineno less by 1 because erb generates a
67
+ # comment before the source code.
68
+ WebAction.class_eval <<-RUBY, filename, -1 # standard:disable Style/EvalWithLocation
69
+ def _erb_#{content}
70
+ #{src}
71
+ end
72
+ RUBY
51
73
  end
52
74
  end
53
75
 
@@ -68,22 +90,22 @@ module Sidekiq
68
90
  end
69
91
 
70
92
  def json(payload)
71
- [200, { "Content-Type" => "application/json", "Cache-Control" => "no-cache" }, [Sidekiq.dump_json(payload)]]
93
+ [200, {Rack::CONTENT_TYPE => "application/json", Rack::CACHE_CONTROL => "private, no-store"}, [Sidekiq.dump_json(payload)]]
72
94
  end
73
95
 
74
96
  def initialize(env, block)
75
97
  @_erb = false
76
98
  @env = env
77
99
  @block = block
78
- @@files ||= {}
100
+ @files ||= {}
79
101
  end
80
102
 
81
103
  private
82
104
 
83
105
  def _erb(file, locals)
84
- locals.each {|k, v| define_singleton_method(k){ v } } if locals
106
+ locals&.each { |k, v| define_singleton_method(k) { v } unless singleton_methods.include? k }
85
107
 
86
- if file.kind_of?(String)
108
+ if file.is_a?(String)
87
109
  ERB.new(file).result(binding)
88
110
  else
89
111
  send(:"_erb_#{file}")