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.
- checksums.yaml +5 -5
- data/Changes.md +992 -6
- data/LICENSE.txt +9 -0
- data/README.md +52 -43
- data/bin/sidekiq +22 -4
- data/bin/sidekiqload +209 -115
- data/bin/sidekiqmon +11 -0
- data/lib/generators/sidekiq/job_generator.rb +57 -0
- data/lib/generators/sidekiq/templates/{worker.rb.erb → job.rb.erb} +2 -2
- data/lib/generators/sidekiq/templates/job_spec.rb.erb +6 -0
- data/lib/generators/sidekiq/templates/job_test.rb.erb +8 -0
- data/lib/sidekiq/api.rb +633 -295
- data/lib/sidekiq/capsule.rb +127 -0
- data/lib/sidekiq/cli.rb +270 -248
- data/lib/sidekiq/client.rb +139 -108
- data/lib/sidekiq/component.rb +68 -0
- data/lib/sidekiq/config.rb +287 -0
- data/lib/sidekiq/deploy.rb +62 -0
- data/lib/sidekiq/embedded.rb +61 -0
- data/lib/sidekiq/fetch.rb +53 -121
- data/lib/sidekiq/job.rb +374 -0
- data/lib/sidekiq/job_logger.rb +51 -0
- data/lib/sidekiq/job_retry.rb +301 -0
- data/lib/sidekiq/job_util.rb +107 -0
- data/lib/sidekiq/launcher.rb +241 -69
- data/lib/sidekiq/logger.rb +131 -0
- data/lib/sidekiq/manager.rb +88 -190
- data/lib/sidekiq/metrics/query.rb +155 -0
- data/lib/sidekiq/metrics/shared.rb +95 -0
- data/lib/sidekiq/metrics/tracking.rb +136 -0
- data/lib/sidekiq/middleware/chain.rb +114 -56
- data/lib/sidekiq/middleware/current_attributes.rb +95 -0
- data/lib/sidekiq/middleware/i18n.rb +8 -7
- data/lib/sidekiq/middleware/modules.rb +21 -0
- data/lib/sidekiq/monitor.rb +146 -0
- data/lib/sidekiq/paginator.rb +29 -16
- data/lib/sidekiq/processor.rb +238 -118
- data/lib/sidekiq/rails.rb +57 -27
- data/lib/sidekiq/redis_client_adapter.rb +111 -0
- data/lib/sidekiq/redis_connection.rb +49 -50
- data/lib/sidekiq/ring_buffer.rb +29 -0
- data/lib/sidekiq/scheduled.rb +173 -52
- data/lib/sidekiq/sd_notify.rb +149 -0
- data/lib/sidekiq/systemd.rb +24 -0
- data/lib/sidekiq/testing/inline.rb +7 -5
- data/lib/sidekiq/testing.rb +197 -65
- data/lib/sidekiq/transaction_aware_client.rb +44 -0
- data/lib/sidekiq/version.rb +4 -1
- data/lib/sidekiq/web/action.rb +93 -0
- data/lib/sidekiq/web/application.rb +463 -0
- data/lib/sidekiq/web/csrf_protection.rb +180 -0
- data/lib/sidekiq/web/helpers.rb +364 -0
- data/lib/sidekiq/web/router.rb +104 -0
- data/lib/sidekiq/web.rb +113 -216
- data/lib/sidekiq/worker_compatibility_alias.rb +13 -0
- data/lib/sidekiq.rb +99 -142
- data/sidekiq.gemspec +26 -23
- data/web/assets/images/apple-touch-icon.png +0 -0
- data/web/assets/javascripts/application.js +163 -74
- data/web/assets/javascripts/base-charts.js +106 -0
- data/web/assets/javascripts/chart.min.js +13 -0
- data/web/assets/javascripts/chartjs-plugin-annotation.min.js +7 -0
- data/web/assets/javascripts/dashboard-charts.js +182 -0
- data/web/assets/javascripts/dashboard.js +37 -280
- data/web/assets/javascripts/metrics.js +298 -0
- data/web/assets/stylesheets/application-dark.css +147 -0
- data/web/assets/stylesheets/application-rtl.css +153 -0
- data/web/assets/stylesheets/application.css +181 -198
- data/web/assets/stylesheets/bootstrap-rtl.min.css +9 -0
- data/web/assets/stylesheets/bootstrap.css +4 -8
- data/web/locales/ar.yml +87 -0
- data/web/locales/cs.yml +62 -52
- data/web/locales/da.yml +60 -53
- data/web/locales/de.yml +65 -53
- data/web/locales/el.yml +43 -24
- data/web/locales/en.yml +86 -62
- data/web/locales/es.yml +70 -53
- data/web/locales/fa.yml +80 -0
- data/web/locales/fr.yml +86 -56
- data/web/locales/gd.yml +99 -0
- data/web/locales/he.yml +80 -0
- data/web/locales/hi.yml +59 -59
- data/web/locales/it.yml +53 -53
- data/web/locales/ja.yml +78 -56
- data/web/locales/ko.yml +52 -52
- data/web/locales/lt.yml +83 -0
- data/web/locales/nb.yml +61 -61
- data/web/locales/nl.yml +52 -52
- data/web/locales/pl.yml +45 -45
- data/web/locales/pt-br.yml +83 -55
- data/web/locales/pt.yml +51 -51
- data/web/locales/ru.yml +68 -60
- data/web/locales/sv.yml +53 -53
- data/web/locales/ta.yml +60 -60
- data/web/locales/uk.yml +62 -61
- data/web/locales/ur.yml +80 -0
- data/web/locales/vi.yml +83 -0
- data/web/locales/zh-cn.yml +43 -16
- data/web/locales/zh-tw.yml +42 -8
- data/web/views/_footer.erb +10 -9
- data/web/views/_job_info.erb +26 -5
- data/web/views/_metrics_period_select.erb +12 -0
- data/web/views/_nav.erb +6 -20
- data/web/views/_paging.erb +3 -1
- data/web/views/_poll_link.erb +3 -6
- data/web/views/_summary.erb +7 -7
- data/web/views/busy.erb +87 -28
- data/web/views/dashboard.erb +51 -21
- data/web/views/dead.erb +4 -4
- data/web/views/filtering.erb +7 -0
- data/web/views/layout.erb +15 -5
- data/web/views/metrics.erb +91 -0
- data/web/views/metrics_for_job.erb +59 -0
- data/web/views/morgue.erb +25 -22
- data/web/views/queue.erb +35 -25
- data/web/views/queues.erb +23 -7
- data/web/views/retries.erb +28 -23
- data/web/views/retry.erb +5 -5
- data/web/views/scheduled.erb +19 -17
- data/web/views/scheduled_job_info.erb +1 -1
- metadata +86 -268
- data/.gitignore +0 -12
- data/.travis.yml +0 -16
- data/3.0-Upgrade.md +0 -70
- data/COMM-LICENSE +0 -95
- data/Contributing.md +0 -32
- data/Ent-Changes.md +0 -39
- data/Gemfile +0 -27
- data/LICENSE +0 -9
- data/Pro-2.0-Upgrade.md +0 -138
- data/Pro-Changes.md +0 -454
- data/Rakefile +0 -9
- data/bin/sidekiqctl +0 -93
- data/lib/generators/sidekiq/templates/worker_spec.rb.erb +0 -6
- data/lib/generators/sidekiq/templates/worker_test.rb.erb +0 -8
- data/lib/generators/sidekiq/worker_generator.rb +0 -49
- data/lib/sidekiq/actor.rb +0 -39
- data/lib/sidekiq/core_ext.rb +0 -105
- data/lib/sidekiq/exception_handler.rb +0 -30
- data/lib/sidekiq/extensions/action_mailer.rb +0 -56
- data/lib/sidekiq/extensions/active_record.rb +0 -39
- data/lib/sidekiq/extensions/class_methods.rb +0 -39
- data/lib/sidekiq/extensions/generic_proxy.rb +0 -24
- data/lib/sidekiq/logging.rb +0 -104
- data/lib/sidekiq/middleware/server/active_record.rb +0 -13
- data/lib/sidekiq/middleware/server/logging.rb +0 -40
- data/lib/sidekiq/middleware/server/retry_jobs.rb +0 -206
- data/lib/sidekiq/util.rb +0 -68
- data/lib/sidekiq/web_helpers.rb +0 -249
- data/lib/sidekiq/worker.rb +0 -103
- data/test/config.yml +0 -9
- data/test/env_based_config.yml +0 -11
- data/test/fake_env.rb +0 -0
- data/test/fixtures/en.yml +0 -2
- data/test/helper.rb +0 -49
- data/test/test_api.rb +0 -493
- data/test/test_cli.rb +0 -335
- data/test/test_client.rb +0 -194
- data/test/test_exception_handler.rb +0 -55
- data/test/test_extensions.rb +0 -126
- data/test/test_fetch.rb +0 -104
- data/test/test_logging.rb +0 -34
- data/test/test_manager.rb +0 -168
- data/test/test_middleware.rb +0 -159
- data/test/test_processor.rb +0 -237
- data/test/test_rails.rb +0 -21
- data/test/test_redis_connection.rb +0 -126
- data/test/test_retry.rb +0 -325
- data/test/test_scheduled.rb +0 -114
- data/test/test_scheduling.rb +0 -49
- data/test/test_sidekiq.rb +0 -99
- data/test/test_testing.rb +0 -142
- data/test/test_testing_fake.rb +0 -268
- data/test/test_testing_inline.rb +0 -93
- data/test/test_util.rb +0 -16
- data/test/test_web.rb +0 -608
- data/test/test_web_helpers.rb +0 -53
- data/web/assets/images/bootstrap/glyphicons-halflings-white.png +0 -0
- data/web/assets/images/bootstrap/glyphicons-halflings.png +0 -0
- data/web/assets/images/status/active.png +0 -0
- data/web/assets/images/status/idle.png +0 -0
- data/web/assets/javascripts/locales/README.md +0 -27
- data/web/assets/javascripts/locales/jquery.timeago.ar.js +0 -96
- data/web/assets/javascripts/locales/jquery.timeago.bg.js +0 -18
- data/web/assets/javascripts/locales/jquery.timeago.bs.js +0 -49
- data/web/assets/javascripts/locales/jquery.timeago.ca.js +0 -18
- data/web/assets/javascripts/locales/jquery.timeago.cs.js +0 -18
- data/web/assets/javascripts/locales/jquery.timeago.cy.js +0 -20
- data/web/assets/javascripts/locales/jquery.timeago.da.js +0 -18
- data/web/assets/javascripts/locales/jquery.timeago.de.js +0 -18
- data/web/assets/javascripts/locales/jquery.timeago.el.js +0 -18
- data/web/assets/javascripts/locales/jquery.timeago.en-short.js +0 -20
- data/web/assets/javascripts/locales/jquery.timeago.en.js +0 -20
- data/web/assets/javascripts/locales/jquery.timeago.es.js +0 -18
- data/web/assets/javascripts/locales/jquery.timeago.et.js +0 -18
- data/web/assets/javascripts/locales/jquery.timeago.fa.js +0 -22
- data/web/assets/javascripts/locales/jquery.timeago.fi.js +0 -28
- data/web/assets/javascripts/locales/jquery.timeago.fr-short.js +0 -16
- data/web/assets/javascripts/locales/jquery.timeago.fr.js +0 -17
- data/web/assets/javascripts/locales/jquery.timeago.he.js +0 -18
- data/web/assets/javascripts/locales/jquery.timeago.hr.js +0 -49
- data/web/assets/javascripts/locales/jquery.timeago.hu.js +0 -18
- data/web/assets/javascripts/locales/jquery.timeago.hy.js +0 -18
- data/web/assets/javascripts/locales/jquery.timeago.id.js +0 -18
- data/web/assets/javascripts/locales/jquery.timeago.it.js +0 -16
- data/web/assets/javascripts/locales/jquery.timeago.ja.js +0 -19
- data/web/assets/javascripts/locales/jquery.timeago.ko.js +0 -17
- data/web/assets/javascripts/locales/jquery.timeago.lt.js +0 -20
- data/web/assets/javascripts/locales/jquery.timeago.mk.js +0 -20
- data/web/assets/javascripts/locales/jquery.timeago.nl.js +0 -20
- data/web/assets/javascripts/locales/jquery.timeago.no.js +0 -18
- data/web/assets/javascripts/locales/jquery.timeago.pl.js +0 -31
- data/web/assets/javascripts/locales/jquery.timeago.pt-br.js +0 -16
- data/web/assets/javascripts/locales/jquery.timeago.pt.js +0 -16
- data/web/assets/javascripts/locales/jquery.timeago.ro.js +0 -18
- data/web/assets/javascripts/locales/jquery.timeago.rs.js +0 -49
- data/web/assets/javascripts/locales/jquery.timeago.ru.js +0 -34
- data/web/assets/javascripts/locales/jquery.timeago.sk.js +0 -18
- data/web/assets/javascripts/locales/jquery.timeago.sl.js +0 -44
- data/web/assets/javascripts/locales/jquery.timeago.sv.js +0 -18
- data/web/assets/javascripts/locales/jquery.timeago.th.js +0 -20
- data/web/assets/javascripts/locales/jquery.timeago.tr.js +0 -16
- data/web/assets/javascripts/locales/jquery.timeago.uk.js +0 -34
- data/web/assets/javascripts/locales/jquery.timeago.uz.js +0 -19
- data/web/assets/javascripts/locales/jquery.timeago.zh-cn.js +0 -20
- data/web/assets/javascripts/locales/jquery.timeago.zh-tw.js +0 -20
- data/web/views/_poll_js.erb +0 -5
- /data/web/assets/images/{status-sd8051fd480.png → status.png} +0 -0
data/lib/sidekiq/testing.rb
CHANGED
|
@@ -1,26 +1,46 @@
|
|
|
1
|
-
|
|
2
|
-
require 'sidekiq'
|
|
1
|
+
# frozen_string_literal: true
|
|
3
2
|
|
|
4
|
-
|
|
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 :
|
|
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
|
-
|
|
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.
|
|
25
|
+
self.__local_test_mode = nil
|
|
18
26
|
end
|
|
19
27
|
else
|
|
20
|
-
self.
|
|
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
|
-
|
|
57
|
+
__test_mode != :disable
|
|
38
58
|
end
|
|
39
59
|
|
|
40
60
|
def disabled?
|
|
41
|
-
|
|
61
|
+
__test_mode == :disable
|
|
42
62
|
end
|
|
43
63
|
|
|
44
64
|
def fake?
|
|
45
|
-
|
|
65
|
+
__test_mode == :fake
|
|
46
66
|
end
|
|
47
67
|
|
|
48
68
|
def inline?
|
|
49
|
-
|
|
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
|
-
|
|
66
|
-
|
|
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
|
|
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
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
klass.
|
|
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
|
-
|
|
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
|
|
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,
|
|
103
|
-
#
|
|
104
|
-
# assert_equal 1,
|
|
105
|
-
# assert_equal :something,
|
|
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
|
-
#
|
|
114
|
-
# assert_equal 0, Sidekiq::Extensions::DelayedModel.jobs.size
|
|
231
|
+
# You can also clear and drain all job types:
|
|
115
232
|
#
|
|
116
|
-
#
|
|
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::
|
|
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::
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
159
|
-
|
|
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
|
-
|
|
167
|
-
|
|
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
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
Sidekiq::Testing.server_middleware.invoke(
|
|
175
|
-
execute_job(
|
|
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
|
-
|
|
301
|
+
Queues.jobs_by_queue.values.flatten
|
|
187
302
|
end
|
|
188
303
|
|
|
189
|
-
# Clear all queued jobs
|
|
304
|
+
# Clear all queued jobs
|
|
190
305
|
def clear_all
|
|
191
|
-
|
|
306
|
+
Queues.clear_all
|
|
192
307
|
end
|
|
193
308
|
|
|
194
|
-
# Drain all queued jobs
|
|
309
|
+
# Drain (execute) all queued jobs
|
|
195
310
|
def drain_all
|
|
196
|
-
|
|
197
|
-
jobs.
|
|
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
|
data/lib/sidekiq/version.rb
CHANGED
|
@@ -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
|