sidekiq 3.5.4 → 7.2.0

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 (228) hide show
  1. checksums.yaml +5 -5
  2. data/Changes.md +992 -6
  3. data/LICENSE.txt +9 -0
  4. data/README.md +52 -43
  5. data/bin/sidekiq +22 -4
  6. data/bin/sidekiqload +209 -115
  7. data/bin/sidekiqmon +11 -0
  8. data/lib/generators/sidekiq/job_generator.rb +57 -0
  9. data/lib/generators/sidekiq/templates/{worker.rb.erb → job.rb.erb} +2 -2
  10. data/lib/generators/sidekiq/templates/job_spec.rb.erb +6 -0
  11. data/lib/generators/sidekiq/templates/job_test.rb.erb +8 -0
  12. data/lib/sidekiq/api.rb +633 -295
  13. data/lib/sidekiq/capsule.rb +127 -0
  14. data/lib/sidekiq/cli.rb +270 -248
  15. data/lib/sidekiq/client.rb +139 -108
  16. data/lib/sidekiq/component.rb +68 -0
  17. data/lib/sidekiq/config.rb +287 -0
  18. data/lib/sidekiq/deploy.rb +62 -0
  19. data/lib/sidekiq/embedded.rb +61 -0
  20. data/lib/sidekiq/fetch.rb +53 -121
  21. data/lib/sidekiq/job.rb +374 -0
  22. data/lib/sidekiq/job_logger.rb +51 -0
  23. data/lib/sidekiq/job_retry.rb +301 -0
  24. data/lib/sidekiq/job_util.rb +107 -0
  25. data/lib/sidekiq/launcher.rb +241 -69
  26. data/lib/sidekiq/logger.rb +131 -0
  27. data/lib/sidekiq/manager.rb +88 -190
  28. data/lib/sidekiq/metrics/query.rb +155 -0
  29. data/lib/sidekiq/metrics/shared.rb +95 -0
  30. data/lib/sidekiq/metrics/tracking.rb +136 -0
  31. data/lib/sidekiq/middleware/chain.rb +114 -56
  32. data/lib/sidekiq/middleware/current_attributes.rb +95 -0
  33. data/lib/sidekiq/middleware/i18n.rb +8 -7
  34. data/lib/sidekiq/middleware/modules.rb +21 -0
  35. data/lib/sidekiq/monitor.rb +146 -0
  36. data/lib/sidekiq/paginator.rb +29 -16
  37. data/lib/sidekiq/processor.rb +238 -118
  38. data/lib/sidekiq/rails.rb +57 -27
  39. data/lib/sidekiq/redis_client_adapter.rb +111 -0
  40. data/lib/sidekiq/redis_connection.rb +49 -50
  41. data/lib/sidekiq/ring_buffer.rb +29 -0
  42. data/lib/sidekiq/scheduled.rb +173 -52
  43. data/lib/sidekiq/sd_notify.rb +149 -0
  44. data/lib/sidekiq/systemd.rb +24 -0
  45. data/lib/sidekiq/testing/inline.rb +7 -5
  46. data/lib/sidekiq/testing.rb +197 -65
  47. data/lib/sidekiq/transaction_aware_client.rb +44 -0
  48. data/lib/sidekiq/version.rb +4 -1
  49. data/lib/sidekiq/web/action.rb +93 -0
  50. data/lib/sidekiq/web/application.rb +463 -0
  51. data/lib/sidekiq/web/csrf_protection.rb +180 -0
  52. data/lib/sidekiq/web/helpers.rb +364 -0
  53. data/lib/sidekiq/web/router.rb +104 -0
  54. data/lib/sidekiq/web.rb +113 -216
  55. data/lib/sidekiq/worker_compatibility_alias.rb +13 -0
  56. data/lib/sidekiq.rb +99 -142
  57. data/sidekiq.gemspec +26 -23
  58. data/web/assets/images/apple-touch-icon.png +0 -0
  59. data/web/assets/javascripts/application.js +163 -74
  60. data/web/assets/javascripts/base-charts.js +106 -0
  61. data/web/assets/javascripts/chart.min.js +13 -0
  62. data/web/assets/javascripts/chartjs-plugin-annotation.min.js +7 -0
  63. data/web/assets/javascripts/dashboard-charts.js +182 -0
  64. data/web/assets/javascripts/dashboard.js +37 -280
  65. data/web/assets/javascripts/metrics.js +298 -0
  66. data/web/assets/stylesheets/application-dark.css +147 -0
  67. data/web/assets/stylesheets/application-rtl.css +153 -0
  68. data/web/assets/stylesheets/application.css +181 -198
  69. data/web/assets/stylesheets/bootstrap-rtl.min.css +9 -0
  70. data/web/assets/stylesheets/bootstrap.css +4 -8
  71. data/web/locales/ar.yml +87 -0
  72. data/web/locales/cs.yml +62 -52
  73. data/web/locales/da.yml +60 -53
  74. data/web/locales/de.yml +65 -53
  75. data/web/locales/el.yml +43 -24
  76. data/web/locales/en.yml +86 -62
  77. data/web/locales/es.yml +70 -53
  78. data/web/locales/fa.yml +80 -0
  79. data/web/locales/fr.yml +86 -56
  80. data/web/locales/gd.yml +99 -0
  81. data/web/locales/he.yml +80 -0
  82. data/web/locales/hi.yml +59 -59
  83. data/web/locales/it.yml +53 -53
  84. data/web/locales/ja.yml +78 -56
  85. data/web/locales/ko.yml +52 -52
  86. data/web/locales/lt.yml +83 -0
  87. data/web/locales/nb.yml +61 -61
  88. data/web/locales/nl.yml +52 -52
  89. data/web/locales/pl.yml +45 -45
  90. data/web/locales/pt-br.yml +83 -55
  91. data/web/locales/pt.yml +51 -51
  92. data/web/locales/ru.yml +68 -60
  93. data/web/locales/sv.yml +53 -53
  94. data/web/locales/ta.yml +60 -60
  95. data/web/locales/uk.yml +62 -61
  96. data/web/locales/ur.yml +80 -0
  97. data/web/locales/vi.yml +83 -0
  98. data/web/locales/zh-cn.yml +43 -16
  99. data/web/locales/zh-tw.yml +42 -8
  100. data/web/views/_footer.erb +10 -9
  101. data/web/views/_job_info.erb +26 -5
  102. data/web/views/_metrics_period_select.erb +12 -0
  103. data/web/views/_nav.erb +6 -20
  104. data/web/views/_paging.erb +3 -1
  105. data/web/views/_poll_link.erb +3 -6
  106. data/web/views/_summary.erb +7 -7
  107. data/web/views/busy.erb +87 -28
  108. data/web/views/dashboard.erb +51 -21
  109. data/web/views/dead.erb +4 -4
  110. data/web/views/filtering.erb +7 -0
  111. data/web/views/layout.erb +15 -5
  112. data/web/views/metrics.erb +91 -0
  113. data/web/views/metrics_for_job.erb +59 -0
  114. data/web/views/morgue.erb +25 -22
  115. data/web/views/queue.erb +35 -25
  116. data/web/views/queues.erb +23 -7
  117. data/web/views/retries.erb +28 -23
  118. data/web/views/retry.erb +5 -5
  119. data/web/views/scheduled.erb +19 -17
  120. data/web/views/scheduled_job_info.erb +1 -1
  121. metadata +86 -268
  122. data/.gitignore +0 -12
  123. data/.travis.yml +0 -16
  124. data/3.0-Upgrade.md +0 -70
  125. data/COMM-LICENSE +0 -95
  126. data/Contributing.md +0 -32
  127. data/Ent-Changes.md +0 -39
  128. data/Gemfile +0 -27
  129. data/LICENSE +0 -9
  130. data/Pro-2.0-Upgrade.md +0 -138
  131. data/Pro-Changes.md +0 -454
  132. data/Rakefile +0 -9
  133. data/bin/sidekiqctl +0 -93
  134. data/lib/generators/sidekiq/templates/worker_spec.rb.erb +0 -6
  135. data/lib/generators/sidekiq/templates/worker_test.rb.erb +0 -8
  136. data/lib/generators/sidekiq/worker_generator.rb +0 -49
  137. data/lib/sidekiq/actor.rb +0 -39
  138. data/lib/sidekiq/core_ext.rb +0 -105
  139. data/lib/sidekiq/exception_handler.rb +0 -30
  140. data/lib/sidekiq/extensions/action_mailer.rb +0 -56
  141. data/lib/sidekiq/extensions/active_record.rb +0 -39
  142. data/lib/sidekiq/extensions/class_methods.rb +0 -39
  143. data/lib/sidekiq/extensions/generic_proxy.rb +0 -24
  144. data/lib/sidekiq/logging.rb +0 -104
  145. data/lib/sidekiq/middleware/server/active_record.rb +0 -13
  146. data/lib/sidekiq/middleware/server/logging.rb +0 -40
  147. data/lib/sidekiq/middleware/server/retry_jobs.rb +0 -206
  148. data/lib/sidekiq/util.rb +0 -68
  149. data/lib/sidekiq/web_helpers.rb +0 -249
  150. data/lib/sidekiq/worker.rb +0 -103
  151. data/test/config.yml +0 -9
  152. data/test/env_based_config.yml +0 -11
  153. data/test/fake_env.rb +0 -0
  154. data/test/fixtures/en.yml +0 -2
  155. data/test/helper.rb +0 -49
  156. data/test/test_api.rb +0 -493
  157. data/test/test_cli.rb +0 -335
  158. data/test/test_client.rb +0 -194
  159. data/test/test_exception_handler.rb +0 -55
  160. data/test/test_extensions.rb +0 -126
  161. data/test/test_fetch.rb +0 -104
  162. data/test/test_logging.rb +0 -34
  163. data/test/test_manager.rb +0 -168
  164. data/test/test_middleware.rb +0 -159
  165. data/test/test_processor.rb +0 -237
  166. data/test/test_rails.rb +0 -21
  167. data/test/test_redis_connection.rb +0 -126
  168. data/test/test_retry.rb +0 -325
  169. data/test/test_scheduled.rb +0 -114
  170. data/test/test_scheduling.rb +0 -49
  171. data/test/test_sidekiq.rb +0 -99
  172. data/test/test_testing.rb +0 -142
  173. data/test/test_testing_fake.rb +0 -268
  174. data/test/test_testing_inline.rb +0 -93
  175. data/test/test_util.rb +0 -16
  176. data/test/test_web.rb +0 -608
  177. data/test/test_web_helpers.rb +0 -53
  178. data/web/assets/images/bootstrap/glyphicons-halflings-white.png +0 -0
  179. data/web/assets/images/bootstrap/glyphicons-halflings.png +0 -0
  180. data/web/assets/images/status/active.png +0 -0
  181. data/web/assets/images/status/idle.png +0 -0
  182. data/web/assets/javascripts/locales/README.md +0 -27
  183. data/web/assets/javascripts/locales/jquery.timeago.ar.js +0 -96
  184. data/web/assets/javascripts/locales/jquery.timeago.bg.js +0 -18
  185. data/web/assets/javascripts/locales/jquery.timeago.bs.js +0 -49
  186. data/web/assets/javascripts/locales/jquery.timeago.ca.js +0 -18
  187. data/web/assets/javascripts/locales/jquery.timeago.cs.js +0 -18
  188. data/web/assets/javascripts/locales/jquery.timeago.cy.js +0 -20
  189. data/web/assets/javascripts/locales/jquery.timeago.da.js +0 -18
  190. data/web/assets/javascripts/locales/jquery.timeago.de.js +0 -18
  191. data/web/assets/javascripts/locales/jquery.timeago.el.js +0 -18
  192. data/web/assets/javascripts/locales/jquery.timeago.en-short.js +0 -20
  193. data/web/assets/javascripts/locales/jquery.timeago.en.js +0 -20
  194. data/web/assets/javascripts/locales/jquery.timeago.es.js +0 -18
  195. data/web/assets/javascripts/locales/jquery.timeago.et.js +0 -18
  196. data/web/assets/javascripts/locales/jquery.timeago.fa.js +0 -22
  197. data/web/assets/javascripts/locales/jquery.timeago.fi.js +0 -28
  198. data/web/assets/javascripts/locales/jquery.timeago.fr-short.js +0 -16
  199. data/web/assets/javascripts/locales/jquery.timeago.fr.js +0 -17
  200. data/web/assets/javascripts/locales/jquery.timeago.he.js +0 -18
  201. data/web/assets/javascripts/locales/jquery.timeago.hr.js +0 -49
  202. data/web/assets/javascripts/locales/jquery.timeago.hu.js +0 -18
  203. data/web/assets/javascripts/locales/jquery.timeago.hy.js +0 -18
  204. data/web/assets/javascripts/locales/jquery.timeago.id.js +0 -18
  205. data/web/assets/javascripts/locales/jquery.timeago.it.js +0 -16
  206. data/web/assets/javascripts/locales/jquery.timeago.ja.js +0 -19
  207. data/web/assets/javascripts/locales/jquery.timeago.ko.js +0 -17
  208. data/web/assets/javascripts/locales/jquery.timeago.lt.js +0 -20
  209. data/web/assets/javascripts/locales/jquery.timeago.mk.js +0 -20
  210. data/web/assets/javascripts/locales/jquery.timeago.nl.js +0 -20
  211. data/web/assets/javascripts/locales/jquery.timeago.no.js +0 -18
  212. data/web/assets/javascripts/locales/jquery.timeago.pl.js +0 -31
  213. data/web/assets/javascripts/locales/jquery.timeago.pt-br.js +0 -16
  214. data/web/assets/javascripts/locales/jquery.timeago.pt.js +0 -16
  215. data/web/assets/javascripts/locales/jquery.timeago.ro.js +0 -18
  216. data/web/assets/javascripts/locales/jquery.timeago.rs.js +0 -49
  217. data/web/assets/javascripts/locales/jquery.timeago.ru.js +0 -34
  218. data/web/assets/javascripts/locales/jquery.timeago.sk.js +0 -18
  219. data/web/assets/javascripts/locales/jquery.timeago.sl.js +0 -44
  220. data/web/assets/javascripts/locales/jquery.timeago.sv.js +0 -18
  221. data/web/assets/javascripts/locales/jquery.timeago.th.js +0 -20
  222. data/web/assets/javascripts/locales/jquery.timeago.tr.js +0 -16
  223. data/web/assets/javascripts/locales/jquery.timeago.uk.js +0 -34
  224. data/web/assets/javascripts/locales/jquery.timeago.uz.js +0 -19
  225. data/web/assets/javascripts/locales/jquery.timeago.zh-cn.js +0 -20
  226. data/web/assets/javascripts/locales/jquery.timeago.zh-tw.js +0 -20
  227. data/web/views/_poll_js.erb +0 -5
  228. /data/web/assets/images/{status-sd8051fd480.png → status.png} +0 -0
@@ -1,26 +1,46 @@
1
- require 'securerandom'
2
- require 'sidekiq'
1
+ # frozen_string_literal: true
3
2
 
4
- module Sidekiq
3
+ require "securerandom"
4
+ require "sidekiq"
5
5
 
6
+ module Sidekiq
6
7
  class Testing
8
+ class TestModeAlreadySetError < RuntimeError; end
7
9
  class << self
8
- attr_accessor :__test_mode
10
+ attr_accessor :__global_test_mode
9
11
 
12
+ # Calling without a block sets the global test mode, affecting
13
+ # all threads. Calling with a block only affects the current Thread.
10
14
  def __set_test_mode(mode)
11
15
  if block_given?
12
- 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
13
22
  begin
14
- self.__test_mode = mode
15
23
  yield
16
24
  ensure
17
- self.__test_mode = current_mode
25
+ self.__local_test_mode = nil
18
26
  end
19
27
  else
20
- self.__test_mode = mode
28
+ self.__global_test_mode = mode
21
29
  end
22
30
  end
23
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
+
24
44
  def disable!(&block)
25
45
  __set_test_mode(:disable, &block)
26
46
  end
@@ -34,23 +54,23 @@ module Sidekiq
34
54
  end
35
55
 
36
56
  def enabled?
37
- self.__test_mode != :disable
57
+ __test_mode != :disable
38
58
  end
39
59
 
40
60
  def disabled?
41
- self.__test_mode == :disable
61
+ __test_mode == :disable
42
62
  end
43
63
 
44
64
  def fake?
45
- self.__test_mode == :fake
65
+ __test_mode == :fake
46
66
  end
47
67
 
48
68
  def inline?
49
- self.__test_mode == :inline
69
+ __test_mode == :inline
50
70
  end
51
71
 
52
72
  def server_middleware
53
- @server_chain ||= Middleware::Chain.new
73
+ @server_chain ||= Middleware::Chain.new(Sidekiq.default_configuration)
54
74
  yield @server_chain if block_given?
55
75
  @server_chain
56
76
  end
@@ -62,30 +82,134 @@ module Sidekiq
62
82
 
63
83
  class EmptyQueueError < RuntimeError; end
64
84
 
65
- class Client
66
- alias_method :raw_push_real, :raw_push
67
-
68
- def raw_push(payloads)
85
+ module TestingClient
86
+ def atomic_push(conn, payloads)
69
87
  if Sidekiq::Testing.fake?
70
88
  payloads.each do |job|
71
- job['class'].constantize.jobs << Sidekiq.load_json(Sidekiq.dump_json(job))
89
+ job = Sidekiq.load_json(Sidekiq.dump_json(job))
90
+ job["enqueued_at"] = Time.now.to_f unless job["at"]
91
+ Queues.push(job["queue"], job["class"], job)
72
92
  end
73
93
  true
74
94
  elsif Sidekiq::Testing.inline?
75
95
  payloads.each do |job|
76
- job['jid'] ||= SecureRandom.hex(12)
77
- klass = job['class'].constantize
78
- klass.jobs.unshift Sidekiq.load_json(Sidekiq.dump_json(job))
79
- klass.perform_one
96
+ klass = Object.const_get(job["class"])
97
+ job["id"] ||= SecureRandom.hex(12)
98
+ job_hash = Sidekiq.load_json(Sidekiq.dump_json(job))
99
+ klass.process_job(job_hash)
80
100
  end
81
101
  true
82
102
  else
83
- raw_push_real(payloads)
103
+ super
104
+ end
105
+ end
106
+ end
107
+
108
+ Sidekiq::Client.prepend TestingClient
109
+
110
+ module Queues
111
+ ##
112
+ # The Queues class is only for testing the fake queue implementation.
113
+ # There are 2 data structures involved in tandem. This is due to the
114
+ # Rspec syntax of change(HardJob.jobs, :size). It keeps a reference
115
+ # to the array. Because the array was dervied from a filter of the total
116
+ # jobs enqueued, it appeared as though the array didn't change.
117
+ #
118
+ # To solve this, we'll keep 2 hashes containing the jobs. One with keys based
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.
121
+ #
122
+ # Queue-based hash:
123
+ #
124
+ # {
125
+ # "default"=>[
126
+ # {
127
+ # "class"=>"TestTesting::HardJob",
128
+ # "args"=>[1, 2],
129
+ # "retry"=>true,
130
+ # "queue"=>"default",
131
+ # "jid"=>"abc5b065c5c4b27fc1102833",
132
+ # "created_at"=>1447445554.419934
133
+ # }
134
+ # ]
135
+ # }
136
+ #
137
+ # Job-based hash:
138
+ #
139
+ # {
140
+ # "TestTesting::HardJob"=>[
141
+ # {
142
+ # "class"=>"TestTesting::HardJob",
143
+ # "args"=>[1, 2],
144
+ # "retry"=>true,
145
+ # "queue"=>"default",
146
+ # "jid"=>"abc5b065c5c4b27fc1102833",
147
+ # "created_at"=>1447445554.419934
148
+ # }
149
+ # ]
150
+ # }
151
+ #
152
+ # Example:
153
+ #
154
+ # require 'sidekiq/testing'
155
+ #
156
+ # assert_equal 0, Sidekiq::Queues["default"].size
157
+ # HardJob.perform_async(:something)
158
+ # assert_equal 1, Sidekiq::Queues["default"].size
159
+ # assert_equal :something, Sidekiq::Queues["default"].first['args'][0]
160
+ #
161
+ # You can also clear all jobs:
162
+ #
163
+ # assert_equal 0, Sidekiq::Queues["default"].size
164
+ # HardJob.perform_async(:something)
165
+ # Sidekiq::Queues.clear_all
166
+ # assert_equal 0, Sidekiq::Queues["default"].size
167
+ #
168
+ # This can be useful to make sure jobs don't linger between tests:
169
+ #
170
+ # RSpec.configure do |config|
171
+ # config.before(:each) do
172
+ # Sidekiq::Queues.clear_all
173
+ # end
174
+ # end
175
+ #
176
+ class << self
177
+ def [](queue)
178
+ jobs_by_queue[queue]
179
+ end
180
+
181
+ def push(queue, klass, job)
182
+ jobs_by_queue[queue] << job
183
+ jobs_by_class[klass] << job
184
+ end
185
+
186
+ def jobs_by_queue
187
+ @jobs_by_queue ||= Hash.new { |hash, key| hash[key] = [] }
188
+ end
189
+
190
+ def jobs_by_class
191
+ @jobs_by_class ||= Hash.new { |hash, key| hash[key] = [] }
192
+ end
193
+ alias_method :jobs_by_worker, :jobs_by_class
194
+
195
+ def delete_for(jid, queue, klass)
196
+ jobs_by_queue[queue.to_s].delete_if { |job| job["jid"] == jid }
197
+ jobs_by_class[klass].delete_if { |job| job["jid"] == jid }
198
+ end
199
+
200
+ def clear_for(queue, klass)
201
+ jobs_by_queue[queue.to_s].clear
202
+ jobs_by_class[klass].clear
203
+ end
204
+
205
+ def clear_all
206
+ jobs_by_queue.clear
207
+ jobs_by_class.clear
84
208
  end
85
209
  end
86
210
  end
87
211
 
88
- module Worker
212
+ module Job
89
213
  ##
90
214
  # The Sidekiq testing infrastructure overrides perform_async
91
215
  # so that it does not actually touch the network. Instead it
@@ -99,80 +223,71 @@ module Sidekiq
99
223
  #
100
224
  # require 'sidekiq/testing'
101
225
  #
102
- # assert_equal 0, HardWorker.jobs.size
103
- # HardWorker.perform_async(:something)
104
- # assert_equal 1, HardWorker.jobs.size
105
- # assert_equal :something, HardWorker.jobs[0]['args'][0]
106
- #
107
- # assert_equal 0, Sidekiq::Extensions::DelayedMailer.jobs.size
108
- # MyMailer.delay.send_welcome_email('foo@example.com')
109
- # assert_equal 1, Sidekiq::Extensions::DelayedMailer.jobs.size
110
- #
111
- # You can also clear and drain all workers' jobs:
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]
112
230
  #
113
- # assert_equal 0, Sidekiq::Extensions::DelayedMailer.jobs.size
114
- # assert_equal 0, Sidekiq::Extensions::DelayedModel.jobs.size
231
+ # You can also clear and drain all job types:
115
232
  #
116
- # MyMailer.delay.send_welcome_email('foo@example.com')
117
- # MyModel.delay.do_something_hard
118
- #
119
- # assert_equal 1, Sidekiq::Extensions::DelayedMailer.jobs.size
120
- # assert_equal 1, Sidekiq::Extensions::DelayedModel.jobs.size
121
- #
122
- # Sidekiq::Worker.clear_all # or .drain_all
123
- #
124
- # assert_equal 0, Sidekiq::Extensions::DelayedMailer.jobs.size
125
- # assert_equal 0, Sidekiq::Extensions::DelayedModel.jobs.size
233
+ # Sidekiq::Job.clear_all # or .drain_all
126
234
  #
127
235
  # This can be useful to make sure jobs don't linger between tests:
128
236
  #
129
237
  # RSpec.configure do |config|
130
238
  # config.before(:each) do
131
- # Sidekiq::Worker.clear_all
239
+ # Sidekiq::Job.clear_all
132
240
  # end
133
241
  # end
134
242
  #
135
243
  # or for acceptance testing, i.e. with cucumber:
136
244
  #
137
245
  # AfterStep do
138
- # Sidekiq::Worker.drain_all
246
+ # Sidekiq::Job.drain_all
139
247
  # end
140
248
  #
141
249
  # When I sign up as "foo@example.com"
142
250
  # Then I should receive a welcome email to "foo@example.com"
143
251
  #
144
252
  module ClassMethods
253
+ # Queue for this worker
254
+ def queue
255
+ get_sidekiq_options["queue"]
256
+ end
145
257
 
146
258
  # Jobs queued for this worker
147
259
  def jobs
148
- Worker.jobs[self]
260
+ Queues.jobs_by_class[to_s]
149
261
  end
150
262
 
151
263
  # Clear all jobs for this worker
152
264
  def clear
153
- jobs.clear
265
+ Queues.clear_for(queue, to_s)
154
266
  end
155
267
 
156
268
  # Drain and run all jobs for this worker
157
269
  def drain
158
- while job = jobs.shift do
159
- process_job(job)
270
+ while jobs.any?
271
+ next_job = jobs.first
272
+ Queues.delete_for(next_job["jid"], next_job["queue"], to_s)
273
+ process_job(next_job)
160
274
  end
161
275
  end
162
276
 
163
277
  # Pop out a single job and perform it
164
278
  def perform_one
165
279
  raise(EmptyQueueError, "perform_one called with empty job queue") if jobs.empty?
166
- job = jobs.shift
167
- process_job(job)
280
+ next_job = jobs.first
281
+ Queues.delete_for(next_job["jid"], queue, to_s)
282
+ process_job(next_job)
168
283
  end
169
284
 
170
285
  def process_job(job)
171
- worker = new
172
- worker.jid = job['jid']
173
- worker.bid = job['bid'] if worker.respond_to?(:bid=)
174
- Sidekiq::Testing.server_middleware.invoke(worker, job, job['queue']) do
175
- 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"])
176
291
  end
177
292
  end
178
293
 
@@ -183,20 +298,37 @@ module Sidekiq
183
298
 
184
299
  class << self
185
300
  def jobs # :nodoc:
186
- @jobs ||= Hash.new { |hash, key| hash[key] = [] }
301
+ Queues.jobs_by_queue.values.flatten
187
302
  end
188
303
 
189
- # Clear all queued jobs across all workers
304
+ # Clear all queued jobs
190
305
  def clear_all
191
- jobs.clear
306
+ Queues.clear_all
192
307
  end
193
308
 
194
- # Drain all queued jobs across all workers
309
+ # Drain (execute) all queued jobs
195
310
  def drain_all
196
- until jobs.values.all?(&:empty?) do
197
- jobs.keys.each(&:drain)
311
+ while jobs.any?
312
+ job_classes = jobs.map { |job| job["class"] }.uniq
313
+
314
+ job_classes.each do |job_class|
315
+ Object.const_get(job_class).drain
316
+ end
198
317
  end
199
318
  end
200
319
  end
201
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
330
+ end
331
+
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)
202
334
  end
@@ -0,0 +1,44 @@
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 push(item)
13
+ # pre-allocate the JID so we can return it immediately and
14
+ # save it to the database as part of the transaction.
15
+ item["jid"] ||= SecureRandom.hex(12)
16
+ AfterCommitEverywhere.after_commit { @redis_client.push(item) }
17
+ item["jid"]
18
+ end
19
+
20
+ ##
21
+ # We don't provide transactionality for push_bulk because we don't want
22
+ # to hold potentially hundreds of thousands of job records in memory due to
23
+ # a long running enqueue process.
24
+ def push_bulk(items)
25
+ @redis_client.push_bulk(items)
26
+ end
27
+ end
28
+ end
29
+
30
+ ##
31
+ # Use `Sidekiq.transactional_push!` in your sidekiq.rb initializer
32
+ module Sidekiq
33
+ def self.transactional_push!
34
+ begin
35
+ require "after_commit_everywhere"
36
+ rescue LoadError
37
+ raise %q(You need to add `gem "after_commit_everywhere"` to your Gemfile to use Sidekiq's transactional client)
38
+ end
39
+
40
+ Sidekiq.default_job_options["client_class"] = Sidekiq::TransactionAwareClient
41
+ Sidekiq::JobUtil::TRANSIENT_ATTRIBUTES << "client_class"
42
+ true
43
+ end
44
+ end
@@ -1,3 +1,6 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Sidekiq
2
- VERSION = "3.5.4"
4
+ VERSION = "7.2.0"
5
+ MAJOR = 7
3
6
  end
@@ -0,0 +1,93 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sidekiq
4
+ class WebAction
5
+ RACK_SESSION = "rack.session"
6
+
7
+ attr_accessor :env, :block, :type
8
+
9
+ def settings
10
+ Web.settings
11
+ end
12
+
13
+ def request
14
+ @request ||= ::Rack::Request.new(env)
15
+ end
16
+
17
+ def halt(res)
18
+ throw :halt, [res, {Rack::CONTENT_TYPE => "text/plain"}, [res.to_s]]
19
+ end
20
+
21
+ def redirect(location)
22
+ throw :halt, [302, {Web::LOCATION => "#{request.base_url}#{location}"}, []]
23
+ end
24
+
25
+ def params
26
+ indifferent_hash = Hash.new { |hash, key| hash[key.to_s] if Symbol === key }
27
+
28
+ indifferent_hash.merge! request.params
29
+ route_params.each { |k, v| indifferent_hash[k.to_s] = v }
30
+
31
+ indifferent_hash
32
+ end
33
+
34
+ def route_params
35
+ env[WebRouter::ROUTE_PARAMS]
36
+ end
37
+
38
+ def session
39
+ env[RACK_SESSION]
40
+ end
41
+
42
+ def erb(content, options = {})
43
+ if content.is_a? Symbol
44
+ unless respond_to?(:"_erb_#{content}")
45
+ src = ERB.new(File.read("#{Web.settings.views}/#{content}.erb")).src
46
+ WebAction.class_eval <<-RUBY, __FILE__, __LINE__ + 1
47
+ def _erb_#{content}
48
+ #{src}
49
+ end
50
+ RUBY
51
+ end
52
+ end
53
+
54
+ if @_erb
55
+ _erb(content, options[:locals])
56
+ else
57
+ @_erb = true
58
+ content = _erb(content, options[:locals])
59
+
60
+ _render { content }
61
+ end
62
+ end
63
+
64
+ def render(engine, content, options = {})
65
+ raise "Only erb templates are supported" if engine != :erb
66
+
67
+ erb(content, options)
68
+ end
69
+
70
+ def json(payload)
71
+ [200, {Rack::CONTENT_TYPE => "application/json", Rack::CACHE_CONTROL => "private, no-store"}, [Sidekiq.dump_json(payload)]]
72
+ end
73
+
74
+ def initialize(env, block)
75
+ @_erb = false
76
+ @env = env
77
+ @block = block
78
+ @files ||= {}
79
+ end
80
+
81
+ private
82
+
83
+ def _erb(file, locals)
84
+ locals&.each { |k, v| define_singleton_method(k) { v } unless singleton_methods.include? k }
85
+
86
+ if file.is_a?(String)
87
+ ERB.new(file).result(binding)
88
+ else
89
+ send(:"_erb_#{file}")
90
+ end
91
+ end
92
+ end
93
+ end