sidekiq 6.5.6 → 7.0.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of sidekiq might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/Changes.md +16 -4
- data/{LICENSE → LICENSE.txt} +0 -0
- data/README.md +13 -12
- data/bin/sidekiq +3 -8
- data/bin/sidekiqload +15 -24
- data/lib/sidekiq/api.rb +55 -111
- data/lib/sidekiq/capsule.rb +110 -0
- data/lib/sidekiq/cli.rb +44 -47
- data/lib/sidekiq/client.rb +29 -16
- data/lib/sidekiq/component.rb +1 -0
- data/lib/sidekiq/config.rb +270 -0
- data/lib/sidekiq/deploy.rb +62 -0
- data/lib/sidekiq/embedded.rb +61 -0
- data/lib/sidekiq/fetch.rb +10 -11
- data/lib/sidekiq/job.rb +375 -10
- data/lib/sidekiq/job_logger.rb +1 -1
- data/lib/sidekiq/job_retry.rb +8 -8
- data/lib/sidekiq/job_util.rb +4 -4
- data/lib/sidekiq/launcher.rb +36 -46
- data/lib/sidekiq/logger.rb +1 -26
- data/lib/sidekiq/manager.rb +9 -11
- data/lib/sidekiq/metrics/query.rb +2 -2
- data/lib/sidekiq/metrics/shared.rb +4 -3
- data/lib/sidekiq/metrics/tracking.rb +18 -18
- data/lib/sidekiq/middleware/chain.rb +7 -9
- data/lib/sidekiq/middleware/current_attributes.rb +8 -13
- data/lib/sidekiq/pool.rb +7 -0
- data/lib/sidekiq/processor.rb +17 -26
- data/lib/sidekiq/redis_client_adapter.rb +9 -45
- data/lib/sidekiq/redis_connection.rb +11 -111
- data/lib/sidekiq/scheduled.rb +58 -25
- data/lib/sidekiq/testing.rb +4 -32
- data/lib/sidekiq/transaction_aware_client.rb +4 -5
- data/lib/sidekiq/version.rb +1 -1
- data/lib/sidekiq/web/application.rb +1 -1
- data/lib/sidekiq/web/csrf_protection.rb +1 -1
- data/lib/sidekiq/web/helpers.rb +5 -16
- data/lib/sidekiq/web.rb +2 -17
- data/lib/sidekiq/worker_compatibility_alias.rb +13 -0
- data/lib/sidekiq.rb +52 -274
- data/sidekiq.gemspec +29 -5
- data/web/assets/javascripts/base-charts.js +106 -0
- data/web/assets/javascripts/dashboard-charts.js +166 -0
- data/web/assets/javascripts/dashboard.js +3 -223
- data/web/assets/javascripts/metrics.js +90 -116
- data/web/assets/stylesheets/application-rtl.css +2 -91
- data/web/assets/stylesheets/application.css +21 -296
- data/web/locales/ar.yml +70 -70
- data/web/locales/cs.yml +62 -62
- data/web/locales/da.yml +52 -52
- data/web/locales/de.yml +65 -65
- data/web/locales/el.yml +2 -7
- data/web/locales/en.yml +76 -70
- data/web/locales/es.yml +68 -68
- data/web/locales/fa.yml +65 -65
- data/web/locales/fr.yml +67 -67
- data/web/locales/he.yml +65 -64
- data/web/locales/hi.yml +59 -59
- data/web/locales/it.yml +53 -53
- data/web/locales/ja.yml +71 -68
- data/web/locales/ko.yml +52 -52
- data/web/locales/lt.yml +66 -66
- 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 +59 -69
- data/web/locales/pt.yml +51 -51
- data/web/locales/ru.yml +67 -66
- 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 +64 -64
- data/web/locales/vi.yml +67 -67
- data/web/locales/zh-cn.yml +37 -11
- data/web/locales/zh-tw.yml +42 -8
- data/web/views/_footer.erb +5 -2
- data/web/views/dashboard.erb +36 -5
- data/web/views/metrics.erb +30 -19
- data/web/views/metrics_for_job.erb +16 -34
- metadata +59 -30
- data/lib/sidekiq/delay.rb +0 -43
- data/lib/sidekiq/extensions/action_mailer.rb +0 -48
- data/lib/sidekiq/extensions/active_record.rb +0 -43
- data/lib/sidekiq/extensions/class_methods.rb +0 -43
- data/lib/sidekiq/extensions/generic_proxy.rb +0 -33
- data/lib/sidekiq/metrics/deploy.rb +0 -47
- data/lib/sidekiq/worker.rb +0 -367
- data/web/assets/javascripts/graph.js +0 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 31722cec9da8b32488242bbcf40b46f3e2eaf8f9e5f5acefb4be306e6a3521e1
|
4
|
+
data.tar.gz: 625639dd35227dd5c9e36d04e93afbb3f8ae6372c532625453a0d681fac19a65
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9471e077c2122b7b8fe94d075d1203d83d463608485852237ede31f9307b57233bb6cb0ba867f8556c080d61b01a5eb5efb7f1e3d68835e5bd16adc2630c65e1
|
7
|
+
data.tar.gz: 95b6c47592ba8641b4398859dca9c80b0d644c9e61cffec5482ff5741047daa9523f9cc5efb1974e197f3f06cab07321a5aca8b1838635372b3ea26e37cfca45
|
data/Changes.md
CHANGED
@@ -2,6 +2,18 @@
|
|
2
2
|
|
3
3
|
[Sidekiq Changes](https://github.com/mperham/sidekiq/blob/main/Changes.md) | [Sidekiq Pro Changes](https://github.com/mperham/sidekiq/blob/main/Pro-Changes.md) | [Sidekiq Enterprise Changes](https://github.com/mperham/sidekiq/blob/main/Ent-Changes.md)
|
4
4
|
|
5
|
+
HEAD
|
6
|
+
----------
|
7
|
+
|
8
|
+
- Adjust CurrentAttributes to work with the String class name so we aren't referencing
|
9
|
+
the Class within a Rails initializer [#5536]
|
10
|
+
|
11
|
+
6.5.7
|
12
|
+
----------
|
13
|
+
|
14
|
+
- Updates for JA and ZH locales
|
15
|
+
- Further optimizations for scheduled polling [#5513]
|
16
|
+
|
5
17
|
6.5.6
|
6
18
|
----------
|
7
19
|
|
@@ -564,7 +576,7 @@ Sidekiq::Middleware::Server::Logging -> Sidekiq::JobLogger
|
|
564
576
|
- The `SomeWorker.set(options)` API was re-written to avoid thread-local state. [#2152]
|
565
577
|
- Sidekiq Enterprise's encrypted jobs now display "[encrypted data]" in the Web UI instead
|
566
578
|
of random hex bytes.
|
567
|
-
- Please see the [5.0 Upgrade notes](5.0-Upgrade.md) for more detail.
|
579
|
+
- Please see the [5.0 Upgrade notes](docs/5.0-Upgrade.md) for more detail.
|
568
580
|
|
569
581
|
4.2.10
|
570
582
|
-----------
|
@@ -782,7 +794,7 @@ Sidekiq::Queues.clear_all
|
|
782
794
|
- Sidekiq's internals have been completely overhauled for performance
|
783
795
|
and to remove dependencies. This has resulted in major speedups, as
|
784
796
|
[detailed on my blog](http://www.mikeperham.com/2015/10/14/optimizing-sidekiq/).
|
785
|
-
- See the [4.0 upgrade notes](4.0-Upgrade.md) for more detail.
|
797
|
+
- See the [4.0 upgrade notes](docs/4.0-Upgrade.md) for more detail.
|
786
798
|
|
787
799
|
3.5.4
|
788
800
|
-----------
|
@@ -1049,7 +1061,7 @@ sidekiq_options :dead => false, :retry => 5
|
|
1049
1061
|
3.0.0
|
1050
1062
|
-----------
|
1051
1063
|
|
1052
|
-
Please see [3.0-Upgrade.md](3.0-Upgrade.md) for more comprehensive upgrade notes.
|
1064
|
+
Please see [3.0-Upgrade.md](docs/3.0-Upgrade.md) for more comprehensive upgrade notes.
|
1053
1065
|
|
1054
1066
|
- **Dead Job Queue** - jobs which run out of retries are now moved to a dead
|
1055
1067
|
job queue. These jobs must be retried manually or they will expire
|
@@ -1093,7 +1105,7 @@ Sidekiq::Client.via(ConnectionPool.new { Redis.new }) do
|
|
1093
1105
|
end
|
1094
1106
|
```
|
1095
1107
|
**Sharding support does require a breaking change to client-side
|
1096
|
-
middleware, see 3.0-Upgrade.md.**
|
1108
|
+
middleware, see docs/3.0-Upgrade.md.**
|
1097
1109
|
- New Chinese, Greek, Swedish and Czech translations for the Web UI.
|
1098
1110
|
- Updated most languages translations for the new UI features.
|
1099
1111
|
- **Remove official Capistrano integration** - this integration has been
|
data/{LICENSE → LICENSE.txt}
RENAMED
File without changes
|
data/README.md
CHANGED
@@ -27,10 +27,10 @@ This benchmark can be found in `bin/sidekiqload` and assumes a Redis network lat
|
|
27
27
|
Requirements
|
28
28
|
-----------------
|
29
29
|
|
30
|
-
- Redis:
|
31
|
-
- Ruby: MRI 2.
|
30
|
+
- Redis: 6.2+
|
31
|
+
- Ruby: MRI 2.7+ or JRuby 9.3+.
|
32
32
|
|
33
|
-
Sidekiq
|
33
|
+
Sidekiq 7.0 supports Rails 6.0+ but does not require it.
|
34
34
|
|
35
35
|
|
36
36
|
Installation
|
@@ -52,24 +52,26 @@ Sidekiq and see its features in action. Here's the Web UI:
|
|
52
52
|
Want to Upgrade?
|
53
53
|
-------------------
|
54
54
|
|
55
|
+
Use `bundle up sidekiq` to upgrade Sidekiq and all its dependencies.
|
56
|
+
Upgrade notes between each major version can be found in the `docs/` directory.
|
57
|
+
|
55
58
|
I also sell Sidekiq Pro and Sidekiq Enterprise, extensions to Sidekiq which provide more
|
56
59
|
features, a commercial-friendly license and allow you to support high
|
57
60
|
quality open source development all at the same time. Please see the
|
58
61
|
[Sidekiq](https://sidekiq.org/) homepage for more detail.
|
59
62
|
|
60
|
-
Subscribe to the **[quarterly newsletter](https://tinyletter.com/sidekiq)** to stay informed about the latest
|
61
|
-
features and changes to Sidekiq and its bigger siblings.
|
62
|
-
|
63
63
|
|
64
64
|
Problems?
|
65
65
|
-----------------
|
66
66
|
|
67
|
-
**Please do not directly email any Sidekiq committers with questions or problems.**
|
67
|
+
**Please do not directly email any Sidekiq committers with questions or problems.**
|
68
|
+
A community is best served when discussions are held in public.
|
68
69
|
|
69
70
|
If you have a problem, please review the [FAQ](https://github.com/mperham/sidekiq/wiki/FAQ) and [Troubleshooting](https://github.com/mperham/sidekiq/wiki/Problems-and-Troubleshooting) wiki pages.
|
70
71
|
Searching the [issues](https://github.com/mperham/sidekiq/issues) for your problem is also a good idea.
|
71
72
|
|
72
|
-
Sidekiq Pro and Sidekiq Enterprise customers get private email support.
|
73
|
+
Sidekiq Pro and Sidekiq Enterprise customers get private email support.
|
74
|
+
You can purchase at https://sidekiq.org; email support@contribsys.com for help.
|
73
75
|
|
74
76
|
Useful resources:
|
75
77
|
|
@@ -77,7 +79,7 @@ Useful resources:
|
|
77
79
|
* Occasional announcements are made to the [@sidekiq](https://twitter.com/sidekiq) Twitter account.
|
78
80
|
* The [Sidekiq tag](https://stackoverflow.com/questions/tagged/sidekiq) on Stack Overflow has lots of useful Q & A.
|
79
81
|
|
80
|
-
Every Friday morning is Sidekiq
|
82
|
+
Every Friday morning is Sidekiq office hour: I video chat and answer questions.
|
81
83
|
See the [Sidekiq support page](https://sidekiq.org/support.html) for details.
|
82
84
|
|
83
85
|
Contributing
|
@@ -85,12 +87,11 @@ Contributing
|
|
85
87
|
|
86
88
|
Please see [the contributing guidelines](https://github.com/mperham/sidekiq/blob/main/.github/contributing.md).
|
87
89
|
|
88
|
-
|
89
90
|
License
|
90
91
|
-----------------
|
91
92
|
|
92
|
-
Please see [LICENSE](https://github.com/mperham/sidekiq/blob/main/LICENSE) for licensing details.
|
93
|
-
|
93
|
+
Please see [LICENSE.txt](https://github.com/mperham/sidekiq/blob/main/LICENSE.txt) for licensing details.
|
94
|
+
The license for Sidekiq Pro and Sidekiq Enterprise can be found in [COMM-LICENSE.txt](https://github.com/mperham/sidekiq/blob/main/COMM-LICENSE.txt).
|
94
95
|
|
95
96
|
Author
|
96
97
|
-----------------
|
data/bin/sidekiq
CHANGED
@@ -10,7 +10,7 @@ def integrate_with_systemd
|
|
10
10
|
return unless ENV["NOTIFY_SOCKET"]
|
11
11
|
|
12
12
|
Sidekiq.configure_server do |config|
|
13
|
-
|
13
|
+
config.logger.info "Enabling systemd notification integration"
|
14
14
|
require "sidekiq/sd_notify"
|
15
15
|
config.on(:startup) do
|
16
16
|
Sidekiq::SdNotify.ready
|
@@ -31,12 +31,7 @@ begin
|
|
31
31
|
cli.run
|
32
32
|
rescue => e
|
33
33
|
raise e if $DEBUG
|
34
|
-
|
35
|
-
|
36
|
-
warn e.backtrace.join("\n")
|
37
|
-
else
|
38
|
-
cli.handle_exception e
|
39
|
-
end
|
40
|
-
|
34
|
+
warn e.message
|
35
|
+
warn e.backtrace.join("\n")
|
41
36
|
exit 1
|
42
37
|
end
|
data/bin/sidekiqload
CHANGED
@@ -8,18 +8,11 @@ $TESTING = false
|
|
8
8
|
require "bundler/setup"
|
9
9
|
Bundler.require(:default, :load_test)
|
10
10
|
|
11
|
-
|
12
|
-
require_relative "../lib/sidekiq/launcher"
|
13
|
-
|
14
|
-
if ENV["SIDEKIQ_REDIS_CLIENT"]
|
15
|
-
Sidekiq::RedisConnection.adapter = :redis_client
|
16
|
-
end
|
17
|
-
|
18
|
-
Sidekiq.configure_server do |config|
|
19
|
-
config.options[:concurrency] = 10
|
11
|
+
x = Sidekiq.configure_embed do |config|
|
20
12
|
config.redis = {db: 13, port: 6380}
|
13
|
+
config.concurrency = 10
|
21
14
|
# config.redis = { db: 13, port: 6380, driver: :hiredis}
|
22
|
-
config.
|
15
|
+
config.queues = %w[default]
|
23
16
|
config.logger.level = Logger::ERROR
|
24
17
|
config.average_scheduled_poll_interval = 2
|
25
18
|
config.reliable! if defined?(Sidekiq::Pro)
|
@@ -89,7 +82,7 @@ def Process.rss
|
|
89
82
|
`ps -o rss= -p #{Process.pid}`.chomp.to_i
|
90
83
|
end
|
91
84
|
|
92
|
-
iter =
|
85
|
+
iter = 10
|
93
86
|
count = 10_000
|
94
87
|
|
95
88
|
iter.times do
|
@@ -101,8 +94,8 @@ Sidekiq.logger.error "Created #{count * iter} jobs"
|
|
101
94
|
start = Time.now
|
102
95
|
|
103
96
|
Monitoring = Thread.new do
|
104
|
-
|
105
|
-
sleep 0
|
97
|
+
loop do
|
98
|
+
sleep 1.0
|
106
99
|
qsize = Sidekiq.redis do |conn|
|
107
100
|
conn.llen "queue:default"
|
108
101
|
end
|
@@ -132,30 +125,28 @@ def with_latency(latency, &block)
|
|
132
125
|
end
|
133
126
|
|
134
127
|
begin
|
135
|
-
# RubyProf
|
128
|
+
# RubyProf.exclude_threads = [Monitoring]
|
136
129
|
# RubyProf.start
|
137
|
-
|
138
|
-
events.each(&:call)
|
139
|
-
events.clear
|
140
|
-
|
130
|
+
|
141
131
|
with_latency(Integer(ENV.fetch("LATENCY", "1"))) do
|
142
|
-
|
143
|
-
launcher.run
|
132
|
+
x.run
|
144
133
|
|
145
|
-
while readable_io = IO.select([self_read])
|
134
|
+
while (readable_io = IO.select([self_read]))
|
146
135
|
signal = readable_io.first[0].gets.strip
|
147
|
-
handle_signal(
|
136
|
+
handle_signal(x, signal)
|
148
137
|
end
|
149
138
|
end
|
150
|
-
rescue SystemExit
|
139
|
+
rescue SystemExit
|
151
140
|
# Sidekiq.logger.error("Profiling...")
|
152
141
|
# result = RubyProf.stop
|
153
142
|
# printer = RubyProf::GraphHtmlPrinter.new(result)
|
154
|
-
# printer.print(File.new("output.html", "w"), :
|
143
|
+
# printer.print(File.new("output.html", "w"), min_percent: 1)
|
155
144
|
# normal
|
156
145
|
rescue => e
|
157
146
|
raise e if $DEBUG
|
158
147
|
warn e.message
|
159
148
|
warn e.backtrace.join("\n")
|
160
149
|
exit 1
|
150
|
+
ensure
|
151
|
+
x.stop
|
161
152
|
end
|
data/lib/sidekiq/api.rb
CHANGED
@@ -6,10 +6,18 @@ require "zlib"
|
|
6
6
|
require "set"
|
7
7
|
require "base64"
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
9
|
+
require "sidekiq/metrics/query"
|
10
|
+
|
11
|
+
#
|
12
|
+
# Sidekiq's Data API provides a Ruby object model on top
|
13
|
+
# of Sidekiq's runtime data in Redis. This API should never
|
14
|
+
# be used within application code for business logic.
|
15
|
+
#
|
16
|
+
# The Sidekiq server process never uses this API: all data
|
17
|
+
# manipulation is done directly for performance reasons to
|
18
|
+
# ensure we are using Redis as efficiently as possible at
|
19
|
+
# every callsite.
|
20
|
+
#
|
13
21
|
|
14
22
|
module Sidekiq
|
15
23
|
# Retrieve runtime statistics from Redis regarding
|
@@ -59,7 +67,18 @@ module Sidekiq
|
|
59
67
|
end
|
60
68
|
|
61
69
|
def queues
|
62
|
-
Sidekiq
|
70
|
+
Sidekiq.redis do |conn|
|
71
|
+
queues = conn.sscan("queues").to_a
|
72
|
+
|
73
|
+
lengths = conn.pipelined { |pipeline|
|
74
|
+
queues.each do |queue|
|
75
|
+
pipeline.llen("queue:#{queue}")
|
76
|
+
end
|
77
|
+
}
|
78
|
+
|
79
|
+
array_of_arrays = queues.zip(lengths).sort_by { |_, size| -size }
|
80
|
+
array_of_arrays.to_h
|
81
|
+
end
|
63
82
|
end
|
64
83
|
|
65
84
|
# O(1) redis calls
|
@@ -106,11 +125,11 @@ module Sidekiq
|
|
106
125
|
# @api private
|
107
126
|
def fetch_stats_slow!
|
108
127
|
processes = Sidekiq.redis { |conn|
|
109
|
-
conn.
|
128
|
+
conn.sscan("processes").to_a
|
110
129
|
}
|
111
130
|
|
112
131
|
queues = Sidekiq.redis { |conn|
|
113
|
-
conn.
|
132
|
+
conn.sscan("queues").to_a
|
114
133
|
}
|
115
134
|
|
116
135
|
pipe2_res = Sidekiq.redis { |conn|
|
@@ -122,7 +141,7 @@ module Sidekiq
|
|
122
141
|
|
123
142
|
s = processes.size
|
124
143
|
workers_size = pipe2_res[0...s].sum(&:to_i)
|
125
|
-
enqueued = pipe2_res[s
|
144
|
+
enqueued = pipe2_res[s..].sum(&:to_i)
|
126
145
|
|
127
146
|
@stats[:workers_size] = workers_size
|
128
147
|
@stats[:enqueued] = enqueued
|
@@ -157,25 +176,8 @@ module Sidekiq
|
|
157
176
|
@stats[s] || raise(ArgumentError, "Unknown stat #{s}")
|
158
177
|
end
|
159
178
|
|
160
|
-
class Queues
|
161
|
-
def lengths
|
162
|
-
Sidekiq.redis do |conn|
|
163
|
-
queues = conn.sscan_each("queues").to_a
|
164
|
-
|
165
|
-
lengths = conn.pipelined { |pipeline|
|
166
|
-
queues.each do |queue|
|
167
|
-
pipeline.llen("queue:#{queue}")
|
168
|
-
end
|
169
|
-
}
|
170
|
-
|
171
|
-
array_of_arrays = queues.zip(lengths).sort_by { |_, size| -size }
|
172
|
-
array_of_arrays.to_h
|
173
|
-
end
|
174
|
-
end
|
175
|
-
end
|
176
|
-
|
177
179
|
class History
|
178
|
-
def initialize(days_previous, start_date = nil)
|
180
|
+
def initialize(days_previous, start_date = nil, pool: nil)
|
179
181
|
# we only store five years of data in Redis
|
180
182
|
raise ArgumentError if days_previous < 1 || days_previous > (5 * 365)
|
181
183
|
@days_previous = days_previous
|
@@ -200,15 +202,10 @@ module Sidekiq
|
|
200
202
|
|
201
203
|
keys = dates.map { |datestr| "stat:#{stat}:#{datestr}" }
|
202
204
|
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
stat_hash[dates[idx]] = value ? value.to_i : 0
|
207
|
-
end
|
205
|
+
Sidekiq.redis do |conn|
|
206
|
+
conn.mget(keys).each_with_index do |value, idx|
|
207
|
+
stat_hash[dates[idx]] = value ? value.to_i : 0
|
208
208
|
end
|
209
|
-
rescue RedisConnection.adapter::CommandError
|
210
|
-
# mget will trigger a CROSSSLOT error when run against a Cluster
|
211
|
-
# TODO Someone want to add Cluster support?
|
212
209
|
end
|
213
210
|
|
214
211
|
stat_hash
|
@@ -236,7 +233,7 @@ module Sidekiq
|
|
236
233
|
#
|
237
234
|
# @return [Array<Sidekiq::Queue>]
|
238
235
|
def self.all
|
239
|
-
Sidekiq.redis { |c| c.
|
236
|
+
Sidekiq.redis { |c| c.sscan("queues").to_a }.sort.map { |q| Sidekiq::Queue.new(q) }
|
240
237
|
end
|
241
238
|
|
242
239
|
attr_reader :name
|
@@ -377,12 +374,7 @@ module Sidekiq
|
|
377
374
|
def display_class
|
378
375
|
# Unwrap known wrappers so they show up in a human-friendly manner in the Web UI
|
379
376
|
@klass ||= self["display_class"] || begin
|
380
|
-
|
381
|
-
when /\ASidekiq::Extensions::Delayed/
|
382
|
-
safe_load(args[0], klass) do |target, method, _|
|
383
|
-
"#{target}.#{method}"
|
384
|
-
end
|
385
|
-
when "ActiveJob::QueueAdapters::SidekiqAdapter::JobWrapper"
|
377
|
+
if klass == "ActiveJob::QueueAdapters::SidekiqAdapter::JobWrapper"
|
386
378
|
job_class = @item["wrapped"] || args[0]
|
387
379
|
if job_class == "ActionMailer::DeliveryJob" || job_class == "ActionMailer::MailDeliveryJob"
|
388
380
|
# MailerClass#mailer_method
|
@@ -398,16 +390,7 @@ module Sidekiq
|
|
398
390
|
|
399
391
|
def display_args
|
400
392
|
# Unwrap known wrappers so they show up in a human-friendly manner in the Web UI
|
401
|
-
@display_args ||=
|
402
|
-
when /\ASidekiq::Extensions::Delayed/
|
403
|
-
safe_load(args[0], args) do |_, _, arg, kwarg|
|
404
|
-
if !kwarg || kwarg.empty?
|
405
|
-
arg
|
406
|
-
else
|
407
|
-
[arg, kwarg]
|
408
|
-
end
|
409
|
-
end
|
410
|
-
when "ActiveJob::QueueAdapters::SidekiqAdapter::JobWrapper"
|
393
|
+
@display_args ||= if klass == "ActiveJob::QueueAdapters::SidekiqAdapter::JobWrapper"
|
411
394
|
job_args = self["wrapped"] ? args[0]["arguments"] : []
|
412
395
|
if (self["wrapped"] || args[0]) == "ActionMailer::DeliveryJob"
|
413
396
|
# remove MailerClass, mailer_method and 'deliver_now'
|
@@ -480,31 +463,10 @@ module Sidekiq
|
|
480
463
|
|
481
464
|
private
|
482
465
|
|
483
|
-
def safe_load(content, default)
|
484
|
-
yield(*YAML.load(content))
|
485
|
-
rescue => ex
|
486
|
-
# #1761 in dev mode, it's possible to have jobs enqueued which haven't been loaded into
|
487
|
-
# memory yet so the YAML can't be loaded.
|
488
|
-
# TODO is this still necessary? Zeitwerk reloader should handle?
|
489
|
-
Sidekiq.logger.warn "Unable to load YAML: #{ex.message}" unless Sidekiq.options[:environment] == "development"
|
490
|
-
default
|
491
|
-
end
|
492
|
-
|
493
466
|
def uncompress_backtrace(backtrace)
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
else
|
498
|
-
decoded = Base64.decode64(backtrace)
|
499
|
-
uncompressed = Zlib::Inflate.inflate(decoded)
|
500
|
-
begin
|
501
|
-
Sidekiq.load_json(uncompressed)
|
502
|
-
rescue
|
503
|
-
# Handle old jobs with marshalled backtrace format
|
504
|
-
# TODO Remove in 7.x
|
505
|
-
Marshal.load(uncompressed)
|
506
|
-
end
|
507
|
-
end
|
467
|
+
decoded = Base64.decode64(backtrace)
|
468
|
+
uncompressed = Zlib::Inflate.inflate(decoded)
|
469
|
+
Sidekiq.load_json(uncompressed)
|
508
470
|
end
|
509
471
|
end
|
510
472
|
|
@@ -645,7 +607,7 @@ module Sidekiq
|
|
645
607
|
|
646
608
|
match = "*#{match}*" unless match.include?("*")
|
647
609
|
Sidekiq.redis do |conn|
|
648
|
-
conn.
|
610
|
+
conn.zscan(name, match: match, count: count) do |entry, score|
|
649
611
|
yield SortedEntry.new(self, score, entry)
|
650
612
|
end
|
651
613
|
end
|
@@ -735,7 +697,7 @@ module Sidekiq
|
|
735
697
|
# @return [SortedEntry] the record or nil
|
736
698
|
def find_job(jid)
|
737
699
|
Sidekiq.redis do |conn|
|
738
|
-
conn.
|
700
|
+
conn.zscan(name, match: "*#{jid}*", count: 100) do |entry, score|
|
739
701
|
job = JSON.parse(entry)
|
740
702
|
matched = job["jid"] == jid
|
741
703
|
return SortedEntry.new(self, score, entry) if matched
|
@@ -781,12 +743,8 @@ module Sidekiq
|
|
781
743
|
# example where I'm selecting jobs based on some complex logic
|
782
744
|
# and deleting them from the scheduled set.
|
783
745
|
#
|
784
|
-
#
|
785
|
-
#
|
786
|
-
# scheduled.klass == 'Sidekiq::Extensions::DelayedClass' &&
|
787
|
-
# scheduled.args[0] == 'User' &&
|
788
|
-
# scheduled.args[1] == 'setup_new_subscriber'
|
789
|
-
# end.map(&:delete)
|
746
|
+
# See the API wiki page for usage notes and examples.
|
747
|
+
#
|
790
748
|
class ScheduledSet < JobSet
|
791
749
|
def initialize
|
792
750
|
super "schedule"
|
@@ -799,12 +757,8 @@ module Sidekiq
|
|
799
757
|
# example where I'm selecting all jobs of a certain type
|
800
758
|
# and deleting them from the retry queue.
|
801
759
|
#
|
802
|
-
#
|
803
|
-
#
|
804
|
-
# retri.klass == 'Sidekiq::Extensions::DelayedClass' &&
|
805
|
-
# retri.args[0] == 'User' &&
|
806
|
-
# retri.args[1] == 'setup_new_subscriber'
|
807
|
-
# end.map(&:delete)
|
760
|
+
# See the API wiki page for usage notes and examples.
|
761
|
+
#
|
808
762
|
class RetrySet < JobSet
|
809
763
|
def initialize
|
810
764
|
super "retry"
|
@@ -838,8 +792,8 @@ module Sidekiq
|
|
838
792
|
Sidekiq.redis do |conn|
|
839
793
|
conn.multi do |transaction|
|
840
794
|
transaction.zadd(name, now.to_s, message)
|
841
|
-
transaction.zremrangebyscore(name, "-inf", now -
|
842
|
-
transaction.zremrangebyrank(name, 0, -
|
795
|
+
transaction.zremrangebyscore(name, "-inf", now - Sidekiq::Config::DEFAULTS[:dead_timeout_in_seconds])
|
796
|
+
transaction.zremrangebyrank(name, 0, - Sidekiq::Config::DEFAULTS[:dead_max_jobs])
|
843
797
|
end
|
844
798
|
end
|
845
799
|
|
@@ -847,7 +801,7 @@ module Sidekiq
|
|
847
801
|
job = Sidekiq.load_json(message)
|
848
802
|
r = RuntimeError.new("Job killed by API")
|
849
803
|
r.set_backtrace(caller)
|
850
|
-
Sidekiq.death_handlers.each do |handle|
|
804
|
+
Sidekiq.default_configuration.death_handlers.each do |handle|
|
851
805
|
handle.call(job, r)
|
852
806
|
end
|
853
807
|
end
|
@@ -858,18 +812,6 @@ module Sidekiq
|
|
858
812
|
def retry_all
|
859
813
|
each(&:retry) while size > 0
|
860
814
|
end
|
861
|
-
|
862
|
-
# The maximum size of the Dead set. Older entries will be trimmed
|
863
|
-
# to stay within this limit. Default value is 10,000.
|
864
|
-
def self.max_jobs
|
865
|
-
Sidekiq[:dead_max_jobs]
|
866
|
-
end
|
867
|
-
|
868
|
-
# The time limit for entries within the Dead set. Older entries will be thrown away.
|
869
|
-
# Default value is six months.
|
870
|
-
def self.timeout
|
871
|
-
Sidekiq[:dead_timeout_in_seconds]
|
872
|
-
end
|
873
815
|
end
|
874
816
|
|
875
817
|
##
|
@@ -893,10 +835,12 @@ module Sidekiq
|
|
893
835
|
# :nodoc:
|
894
836
|
# @api private
|
895
837
|
def cleanup
|
838
|
+
# dont run cleanup more than once per minute
|
896
839
|
return 0 unless Sidekiq.redis { |conn| conn.set("process_cleanup", "1", nx: true, ex: 60) }
|
840
|
+
|
897
841
|
count = 0
|
898
842
|
Sidekiq.redis do |conn|
|
899
|
-
procs = conn.
|
843
|
+
procs = conn.sscan("processes").to_a
|
900
844
|
heartbeats = conn.pipelined { |pipeline|
|
901
845
|
procs.each do |key|
|
902
846
|
pipeline.hget(key, "info")
|
@@ -916,7 +860,7 @@ module Sidekiq
|
|
916
860
|
|
917
861
|
def each
|
918
862
|
result = Sidekiq.redis { |conn|
|
919
|
-
procs = conn.
|
863
|
+
procs = conn.sscan("processes").to_a.sort
|
920
864
|
|
921
865
|
# We're making a tradeoff here between consuming more memory instead of
|
922
866
|
# making more roundtrips to Redis, but if you have hundreds or thousands of workers,
|
@@ -1008,7 +952,7 @@ module Sidekiq
|
|
1008
952
|
end
|
1009
953
|
|
1010
954
|
def labels
|
1011
|
-
|
955
|
+
self["labels"].to_a
|
1012
956
|
end
|
1013
957
|
|
1014
958
|
def [](key)
|
@@ -1091,13 +1035,13 @@ module Sidekiq
|
|
1091
1035
|
def each(&block)
|
1092
1036
|
results = []
|
1093
1037
|
Sidekiq.redis do |conn|
|
1094
|
-
procs = conn.
|
1038
|
+
procs = conn.sscan("processes").to_a
|
1095
1039
|
procs.sort.each do |key|
|
1096
1040
|
valid, workers = conn.pipelined { |pipeline|
|
1097
|
-
pipeline.exists
|
1041
|
+
pipeline.exists(key)
|
1098
1042
|
pipeline.hgetall("#{key}:work")
|
1099
1043
|
}
|
1100
|
-
next unless valid
|
1044
|
+
next unless valid > 0
|
1101
1045
|
workers.each_pair do |tid, json|
|
1102
1046
|
hsh = Sidekiq.load_json(json)
|
1103
1047
|
p = hsh["payload"]
|
@@ -1119,7 +1063,7 @@ module Sidekiq
|
|
1119
1063
|
# which can easily get out of sync with crashy processes.
|
1120
1064
|
def size
|
1121
1065
|
Sidekiq.redis do |conn|
|
1122
|
-
procs = conn.
|
1066
|
+
procs = conn.sscan("processes").to_a
|
1123
1067
|
if procs.empty?
|
1124
1068
|
0
|
1125
1069
|
else
|
@@ -0,0 +1,110 @@
|
|
1
|
+
require "sidekiq/component"
|
2
|
+
|
3
|
+
module Sidekiq
|
4
|
+
# A Sidekiq::Capsule is the set of resources necessary to
|
5
|
+
# process one or more queues with a given concurrency.
|
6
|
+
# One "default" Capsule is started but the user may declare additional
|
7
|
+
# Capsules in the initializer.
|
8
|
+
#
|
9
|
+
# To process a "single" queue with one thread so jobs are processed
|
10
|
+
# serially, you can do this:
|
11
|
+
#
|
12
|
+
# Sidekiq.configure_server do |config|
|
13
|
+
# config.capsule("single-threaded") do |cap|
|
14
|
+
# cap.concurrency = 1
|
15
|
+
# cap.queues = %w(single)
|
16
|
+
# end
|
17
|
+
# end
|
18
|
+
class Capsule
|
19
|
+
include Sidekiq::Component
|
20
|
+
|
21
|
+
attr_reader :name
|
22
|
+
attr_reader :queues
|
23
|
+
attr_accessor :concurrency
|
24
|
+
|
25
|
+
def initialize(name, config)
|
26
|
+
@name = name
|
27
|
+
@config = config
|
28
|
+
@queues = ["default"]
|
29
|
+
@concurrency = config[:concurrency]
|
30
|
+
end
|
31
|
+
|
32
|
+
def fetcher
|
33
|
+
@fetcher ||= begin
|
34
|
+
inst = (config[:fetch_class] || Sidekiq::BasicFetch).new(self)
|
35
|
+
inst.setup(config[:fetch_setup]) if inst.respond_to?(:setup)
|
36
|
+
inst
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def stop
|
41
|
+
fetcher&.bulk_requeue([], nil)
|
42
|
+
end
|
43
|
+
|
44
|
+
def queues=(val)
|
45
|
+
@queues = Array(val).each_with_object([]) do |qstr, memo|
|
46
|
+
arr = qstr
|
47
|
+
arr = qstr.split(",") if qstr.is_a?(String)
|
48
|
+
name, weight = arr
|
49
|
+
[weight.to_i, 1].max.times do
|
50
|
+
memo << name
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# Allow the middleware to be different per-capsule.
|
56
|
+
# Avoid if possible and add middleware globally so all
|
57
|
+
# capsules share the same chains. Easier to debug that way.
|
58
|
+
def client_middleware
|
59
|
+
@client_chain ||= config.client_middleware.copy_for(self)
|
60
|
+
yield @client_chain if block_given?
|
61
|
+
@client_chain
|
62
|
+
end
|
63
|
+
|
64
|
+
def server_middleware
|
65
|
+
@server_chain ||= config.server_middleware.copy_for(self)
|
66
|
+
yield @server_chain if block_given?
|
67
|
+
@server_chain
|
68
|
+
end
|
69
|
+
|
70
|
+
def redis_pool
|
71
|
+
Thread.current[:sidekiq_redis_pool] || local_redis_pool
|
72
|
+
end
|
73
|
+
|
74
|
+
def local_redis_pool
|
75
|
+
# connection pool is lazy, it will not create connections unless you actually need them
|
76
|
+
# so don't be skimpy!
|
77
|
+
@redis ||= config.new_redis_pool(@concurrency, name)
|
78
|
+
end
|
79
|
+
|
80
|
+
def redis
|
81
|
+
raise ArgumentError, "requires a block" unless block_given?
|
82
|
+
redis_pool.with do |conn|
|
83
|
+
retryable = true
|
84
|
+
begin
|
85
|
+
yield conn
|
86
|
+
rescue RedisClientAdapter::BaseError => ex
|
87
|
+
# 2550 Failover can cause the server to become a replica, need
|
88
|
+
# to disconnect and reopen the socket to get back to the primary.
|
89
|
+
# 4495 Use the same logic if we have a "Not enough replicas" error from the primary
|
90
|
+
# 4985 Use the same logic when a blocking command is force-unblocked
|
91
|
+
# The same retry logic is also used in client.rb
|
92
|
+
if retryable && ex.message =~ /READONLY|NOREPLICAS|UNBLOCKED/
|
93
|
+
conn.close
|
94
|
+
retryable = false
|
95
|
+
retry
|
96
|
+
end
|
97
|
+
raise
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def lookup(name)
|
103
|
+
config.lookup(name)
|
104
|
+
end
|
105
|
+
|
106
|
+
def logger
|
107
|
+
config.logger
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|