sidekiq 6.5.1 → 7.0.9
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 +4 -4
- data/Changes.md +142 -12
- data/README.md +40 -32
- data/bin/sidekiq +3 -8
- data/bin/sidekiqload +186 -118
- data/bin/sidekiqmon +3 -0
- data/lib/sidekiq/api.rb +226 -139
- data/lib/sidekiq/capsule.rb +127 -0
- data/lib/sidekiq/cli.rb +55 -61
- data/lib/sidekiq/client.rb +31 -18
- data/lib/sidekiq/component.rb +5 -1
- 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 +11 -14
- data/lib/sidekiq/job.rb +375 -10
- data/lib/sidekiq/job_logger.rb +2 -2
- data/lib/sidekiq/job_retry.rb +62 -41
- data/lib/sidekiq/job_util.rb +48 -14
- data/lib/sidekiq/launcher.rb +71 -65
- data/lib/sidekiq/logger.rb +1 -26
- data/lib/sidekiq/manager.rb +9 -11
- data/lib/sidekiq/metrics/query.rb +153 -0
- data/lib/sidekiq/metrics/shared.rb +95 -0
- data/lib/sidekiq/metrics/tracking.rb +136 -0
- data/lib/sidekiq/middleware/chain.rb +84 -48
- data/lib/sidekiq/middleware/current_attributes.rb +12 -17
- data/lib/sidekiq/monitor.rb +17 -4
- data/lib/sidekiq/paginator.rb +9 -1
- data/lib/sidekiq/processor.rb +27 -27
- data/lib/sidekiq/rails.rb +4 -9
- data/lib/sidekiq/redis_client_adapter.rb +8 -47
- data/lib/sidekiq/redis_connection.rb +11 -113
- data/lib/sidekiq/scheduled.rb +60 -33
- data/lib/sidekiq/testing.rb +5 -33
- data/lib/sidekiq/transaction_aware_client.rb +4 -5
- data/lib/sidekiq/version.rb +2 -1
- data/lib/sidekiq/web/action.rb +3 -3
- data/lib/sidekiq/web/application.rb +40 -9
- data/lib/sidekiq/web/csrf_protection.rb +1 -1
- data/lib/sidekiq/web/helpers.rb +32 -18
- data/lib/sidekiq/web.rb +7 -14
- data/lib/sidekiq/worker_compatibility_alias.rb +13 -0
- data/lib/sidekiq.rb +76 -266
- data/sidekiq.gemspec +21 -10
- data/web/assets/javascripts/application.js +19 -1
- 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 +166 -0
- data/web/assets/javascripts/dashboard.js +3 -240
- data/web/assets/javascripts/metrics.js +264 -0
- data/web/assets/stylesheets/application-dark.css +4 -0
- data/web/assets/stylesheets/application-rtl.css +2 -91
- data/web/assets/stylesheets/application.css +65 -297
- data/web/locales/ar.yml +70 -70
- data/web/locales/cs.yml +62 -62
- data/web/locales/da.yml +60 -53
- data/web/locales/de.yml +65 -65
- data/web/locales/el.yml +43 -24
- data/web/locales/en.yml +82 -69
- data/web/locales/es.yml +68 -68
- data/web/locales/fa.yml +65 -65
- data/web/locales/fr.yml +67 -67
- data/web/locales/gd.yml +99 -0
- 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 +73 -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 +43 -16
- data/web/locales/zh-tw.yml +42 -8
- data/web/views/_footer.erb +5 -2
- data/web/views/_job_info.erb +18 -2
- data/web/views/_metrics_period_select.erb +12 -0
- data/web/views/_nav.erb +1 -1
- data/web/views/_paging.erb +2 -0
- data/web/views/_poll_link.erb +1 -1
- data/web/views/busy.erb +43 -27
- data/web/views/dashboard.erb +36 -4
- data/web/views/metrics.erb +82 -0
- data/web/views/metrics_for_job.erb +68 -0
- data/web/views/morgue.erb +5 -9
- data/web/views/queue.erb +15 -15
- data/web/views/queues.erb +3 -1
- data/web/views/retries.erb +5 -9
- data/web/views/scheduled.erb +12 -13
- metadata +60 -27
- data/lib/sidekiq/.DS_Store +0 -0
- 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/worker.rb +0 -367
- /data/{LICENSE → LICENSE.txt} +0 -0
data/lib/sidekiq/web/helpers.rb
CHANGED
|
@@ -15,7 +15,7 @@ module Sidekiq
|
|
|
15
15
|
# so extensions can be localized
|
|
16
16
|
@strings[lang] ||= settings.locales.each_with_object({}) do |path, global|
|
|
17
17
|
find_locale_files(lang).each do |file|
|
|
18
|
-
strs = YAML.
|
|
18
|
+
strs = YAML.safe_load(File.read(file))
|
|
19
19
|
global.merge!(strs[lang])
|
|
20
20
|
end
|
|
21
21
|
end
|
|
@@ -118,7 +118,7 @@ module Sidekiq
|
|
|
118
118
|
}.join(" ")
|
|
119
119
|
end
|
|
120
120
|
|
|
121
|
-
#
|
|
121
|
+
# sidekiq/sidekiq#3243
|
|
122
122
|
def unfiltered?
|
|
123
123
|
yield unless env["PATH_INFO"].start_with?("/filter/")
|
|
124
124
|
end
|
|
@@ -137,7 +137,7 @@ module Sidekiq
|
|
|
137
137
|
end
|
|
138
138
|
|
|
139
139
|
def sort_direction_label
|
|
140
|
-
params[:direction] == "asc" ? "↑" : "↓"
|
|
140
|
+
(params[:direction] == "asc") ? "↑" : "↓"
|
|
141
141
|
end
|
|
142
142
|
|
|
143
143
|
def workset
|
|
@@ -148,22 +148,39 @@ module Sidekiq
|
|
|
148
148
|
@processes ||= Sidekiq::ProcessSet.new
|
|
149
149
|
end
|
|
150
150
|
|
|
151
|
+
# Sorts processes by hostname following the natural sort order
|
|
152
|
+
def sorted_processes
|
|
153
|
+
@sorted_processes ||= begin
|
|
154
|
+
return processes unless processes.all? { |p| p["hostname"] }
|
|
155
|
+
|
|
156
|
+
processes.to_a.sort_by do |process|
|
|
157
|
+
# Kudos to `shurikk` on StackOverflow
|
|
158
|
+
# https://stackoverflow.com/a/15170063/575547
|
|
159
|
+
process["hostname"].split(/(\d+)/).map { |a| /\d+/.match?(a) ? a.to_i : a }
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
def busy_weights(capsule_weights)
|
|
165
|
+
# backwards compat with 7.0.0, remove in 7.1
|
|
166
|
+
cw = [capsule_weights].flatten
|
|
167
|
+
cw.map { |hash|
|
|
168
|
+
hash.map { |name, weight| (weight > 0) ? +name << ": " << weight.to_s : name }.join(", ")
|
|
169
|
+
}.join("; ")
|
|
170
|
+
end
|
|
171
|
+
|
|
151
172
|
def stats
|
|
152
173
|
@stats ||= Sidekiq::Stats.new
|
|
153
174
|
end
|
|
154
175
|
|
|
155
|
-
def
|
|
176
|
+
def redis_url
|
|
156
177
|
Sidekiq.redis do |conn|
|
|
157
|
-
conn.
|
|
178
|
+
conn.config.server_url
|
|
158
179
|
end
|
|
159
180
|
end
|
|
160
181
|
|
|
161
|
-
def namespace
|
|
162
|
-
@ns ||= Sidekiq.redis { |conn| conn.respond_to?(:namespace) ? conn.namespace : nil }
|
|
163
|
-
end
|
|
164
|
-
|
|
165
182
|
def redis_info
|
|
166
|
-
Sidekiq.redis_info
|
|
183
|
+
Sidekiq.default_configuration.redis_info
|
|
167
184
|
end
|
|
168
185
|
|
|
169
186
|
def root_path
|
|
@@ -175,7 +192,7 @@ module Sidekiq
|
|
|
175
192
|
end
|
|
176
193
|
|
|
177
194
|
def current_status
|
|
178
|
-
workset.size == 0 ? "idle" : "active"
|
|
195
|
+
(workset.size == 0) ? "idle" : "active"
|
|
179
196
|
end
|
|
180
197
|
|
|
181
198
|
def relative_time(time)
|
|
@@ -208,7 +225,7 @@ module Sidekiq
|
|
|
208
225
|
end
|
|
209
226
|
|
|
210
227
|
def truncate(text, truncate_after_chars = 2000)
|
|
211
|
-
truncate_after_chars && text.size > truncate_after_chars ? "#{text[0..truncate_after_chars]}..." : text
|
|
228
|
+
(truncate_after_chars && text.size > truncate_after_chars) ? "#{text[0..truncate_after_chars]}..." : text
|
|
212
229
|
end
|
|
213
230
|
|
|
214
231
|
def display_args(args, truncate_after_chars = 2000)
|
|
@@ -301,7 +318,7 @@ module Sidekiq
|
|
|
301
318
|
end
|
|
302
319
|
|
|
303
320
|
def environment_title_prefix
|
|
304
|
-
environment = Sidekiq[:environment] || ENV["APP_ENV"] || ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "development"
|
|
321
|
+
environment = Sidekiq.default_configuration[:environment] || ENV["APP_ENV"] || ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "development"
|
|
305
322
|
|
|
306
323
|
"[#{environment.upcase}] " unless environment == "production"
|
|
307
324
|
end
|
|
@@ -314,11 +331,8 @@ module Sidekiq
|
|
|
314
331
|
Time.now.utc.strftime("%H:%M:%S UTC")
|
|
315
332
|
end
|
|
316
333
|
|
|
317
|
-
def
|
|
318
|
-
|
|
319
|
-
namespace_suffix = namespace.nil? ? "" : "##{namespace}"
|
|
320
|
-
"#{redis_connection}#{namespace_suffix}"
|
|
321
|
-
end
|
|
334
|
+
def pollable?
|
|
335
|
+
!(current_path == "" || current_path.start_with?("metrics"))
|
|
322
336
|
end
|
|
323
337
|
|
|
324
338
|
def retry_or_delete_or_kill(job, params)
|
data/lib/sidekiq/web.rb
CHANGED
|
@@ -30,7 +30,8 @@ module Sidekiq
|
|
|
30
30
|
"Queues" => "queues",
|
|
31
31
|
"Retries" => "retries",
|
|
32
32
|
"Scheduled" => "scheduled",
|
|
33
|
-
"Dead" => "morgue"
|
|
33
|
+
"Dead" => "morgue",
|
|
34
|
+
"Metrics" => "metrics"
|
|
34
35
|
}
|
|
35
36
|
|
|
36
37
|
class << self
|
|
@@ -47,6 +48,10 @@ module Sidekiq
|
|
|
47
48
|
end
|
|
48
49
|
alias_method :tabs, :custom_tabs
|
|
49
50
|
|
|
51
|
+
def custom_job_info_rows
|
|
52
|
+
@custom_job_info_rows ||= []
|
|
53
|
+
end
|
|
54
|
+
|
|
50
55
|
def locales
|
|
51
56
|
@locales ||= LOCALES
|
|
52
57
|
end
|
|
@@ -75,14 +80,6 @@ module Sidekiq
|
|
|
75
80
|
send(:"#{attribute}=", value)
|
|
76
81
|
end
|
|
77
82
|
|
|
78
|
-
def sessions=(val)
|
|
79
|
-
puts "WARNING: Sidekiq::Web.sessions= is no longer relevant and will be removed in Sidekiq 7.0. #{caller(1..1).first}"
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
def session_secret=(val)
|
|
83
|
-
puts "WARNING: Sidekiq::Web.session_secret= is no longer relevant and will be removed in Sidekiq 7.0. #{caller(1..1).first}"
|
|
84
|
-
end
|
|
85
|
-
|
|
86
83
|
attr_accessor :app_url, :redis_pool
|
|
87
84
|
attr_writer :locales, :views
|
|
88
85
|
end
|
|
@@ -129,10 +126,6 @@ module Sidekiq
|
|
|
129
126
|
send(:"#{attribute}=", value)
|
|
130
127
|
end
|
|
131
128
|
|
|
132
|
-
def sessions=(val)
|
|
133
|
-
puts "Sidekiq::Web#sessions= is no longer relevant and will be removed in Sidekiq 7.0. #{caller[2..2].first}"
|
|
134
|
-
end
|
|
135
|
-
|
|
136
129
|
def self.register(extension)
|
|
137
130
|
extension.registered(WebApplication)
|
|
138
131
|
end
|
|
@@ -144,7 +137,7 @@ module Sidekiq
|
|
|
144
137
|
m = middlewares
|
|
145
138
|
|
|
146
139
|
rules = []
|
|
147
|
-
rules = [[:all, {"
|
|
140
|
+
rules = [[:all, {"cache-control" => "public, max-age=86400"}]] unless ENV["SIDEKIQ_WEB_TESTING"]
|
|
148
141
|
|
|
149
142
|
::Rack::Builder.new do
|
|
150
143
|
use Rack::Static, urls: ["/stylesheets", "/images", "/javascripts"],
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Sidekiq
|
|
4
|
+
# Sidekiq::Job is a new alias for Sidekiq::Worker as of Sidekiq 6.3.0.
|
|
5
|
+
# Use `include Sidekiq::Job` rather than `include Sidekiq::Worker`.
|
|
6
|
+
#
|
|
7
|
+
# The term "worker" is too generic and overly confusing, used in several
|
|
8
|
+
# different contexts meaning different things. Many people call a Sidekiq
|
|
9
|
+
# process a "worker". Some people call the thread that executes jobs a
|
|
10
|
+
# "worker". This change brings Sidekiq closer to ActiveJob where your job
|
|
11
|
+
# classes extend ApplicationJob.
|
|
12
|
+
Worker = Job
|
|
13
|
+
end
|
data/lib/sidekiq.rb
CHANGED
|
@@ -1,15 +1,39 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "sidekiq/version"
|
|
4
|
-
fail "Sidekiq #{Sidekiq::VERSION} does not support Ruby versions below 2.
|
|
4
|
+
fail "Sidekiq #{Sidekiq::VERSION} does not support Ruby versions below 2.7.0." if RUBY_PLATFORM != "java" && Gem::Version.new(RUBY_VERSION) < Gem::Version.new("2.7.0")
|
|
5
5
|
|
|
6
|
+
begin
|
|
7
|
+
require "sidekiq-ent/version"
|
|
8
|
+
fail <<~EOM if Gem::Version.new(Sidekiq::Enterprise::VERSION).segments[0] != Sidekiq::MAJOR
|
|
9
|
+
|
|
10
|
+
Sidekiq Enterprise #{Sidekiq::Enterprise::VERSION} does not work with Sidekiq #{Sidekiq::VERSION}.
|
|
11
|
+
Starting with Sidekiq 7, major versions are synchronized so Sidekiq Enterprise 7 works with Sidekiq 7.
|
|
12
|
+
Use `bundle up sidekiq-ent` to upgrade.
|
|
13
|
+
|
|
14
|
+
EOM
|
|
15
|
+
rescue LoadError
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
begin
|
|
19
|
+
require "sidekiq/pro/version"
|
|
20
|
+
fail <<~EOM if Gem::Version.new(Sidekiq::Pro::VERSION).segments[0] != Sidekiq::MAJOR
|
|
21
|
+
|
|
22
|
+
Sidekiq Pro #{Sidekiq::Pro::VERSION} does not work with Sidekiq #{Sidekiq::VERSION}.
|
|
23
|
+
Starting with Sidekiq 7, major versions are synchronized so Sidekiq Pro 7 works with Sidekiq 7.
|
|
24
|
+
Use `bundle up sidekiq-pro` to upgrade.
|
|
25
|
+
|
|
26
|
+
EOM
|
|
27
|
+
rescue LoadError
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
require "sidekiq/config"
|
|
6
31
|
require "sidekiq/logger"
|
|
7
32
|
require "sidekiq/client"
|
|
8
33
|
require "sidekiq/transaction_aware_client"
|
|
9
|
-
require "sidekiq/worker"
|
|
10
34
|
require "sidekiq/job"
|
|
11
|
-
require "sidekiq/
|
|
12
|
-
require "sidekiq/
|
|
35
|
+
require "sidekiq/worker_compatibility_alias"
|
|
36
|
+
require "sidekiq/redis_client_adapter"
|
|
13
37
|
|
|
14
38
|
require "json"
|
|
15
39
|
|
|
@@ -17,312 +41,98 @@ module Sidekiq
|
|
|
17
41
|
NAME = "Sidekiq"
|
|
18
42
|
LICENSE = "See LICENSE and the LGPL-3.0 for licensing details."
|
|
19
43
|
|
|
20
|
-
DEFAULTS = {
|
|
21
|
-
queues: [],
|
|
22
|
-
labels: [],
|
|
23
|
-
concurrency: 10,
|
|
24
|
-
require: ".",
|
|
25
|
-
strict: true,
|
|
26
|
-
environment: nil,
|
|
27
|
-
timeout: 25,
|
|
28
|
-
poll_interval_average: nil,
|
|
29
|
-
average_scheduled_poll_interval: 5,
|
|
30
|
-
on_complex_arguments: :warn,
|
|
31
|
-
error_handlers: [],
|
|
32
|
-
death_handlers: [],
|
|
33
|
-
lifecycle_events: {
|
|
34
|
-
startup: [],
|
|
35
|
-
quiet: [],
|
|
36
|
-
shutdown: [],
|
|
37
|
-
heartbeat: []
|
|
38
|
-
},
|
|
39
|
-
dead_max_jobs: 10_000,
|
|
40
|
-
dead_timeout_in_seconds: 180 * 24 * 60 * 60, # 6 months
|
|
41
|
-
reloader: proc { |&block| block.call }
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
FAKE_INFO = {
|
|
45
|
-
"redis_version" => "9.9.9",
|
|
46
|
-
"uptime_in_days" => "9999",
|
|
47
|
-
"connected_clients" => "9999",
|
|
48
|
-
"used_memory_human" => "9P",
|
|
49
|
-
"used_memory_peak_human" => "9P"
|
|
50
|
-
}
|
|
51
|
-
|
|
52
44
|
def self.❨╯°□°❩╯︵┻━┻
|
|
53
|
-
puts "
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
# config.concurrency = 5
|
|
57
|
-
def self.concurrency=(val)
|
|
58
|
-
self[:concurrency] = Integer(val)
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
# config.queues = %w( high default low ) # strict
|
|
62
|
-
# config.queues = %w( high,3 default,2 low,1 ) # weighted
|
|
63
|
-
# config.queues = %w( feature1,1 feature2,1 feature3,1 ) # random
|
|
64
|
-
#
|
|
65
|
-
# With weighted priority, queue will be checked first (weight / total) of the time.
|
|
66
|
-
# high will be checked first (3/6) or 50% of the time.
|
|
67
|
-
# I'd recommend setting weights between 1-10. Weights in the hundreds or thousands
|
|
68
|
-
# are ridiculous and unnecessarily expensive. You can get random queue ordering
|
|
69
|
-
# by explicitly setting all weights to 1.
|
|
70
|
-
def self.queues=(val)
|
|
71
|
-
self[:queues] = Array(val).each_with_object([]) do |qstr, memo|
|
|
72
|
-
name, weight = qstr.split(",")
|
|
73
|
-
self[:strict] = false if weight.to_i > 0
|
|
74
|
-
[weight.to_i, 1].max.times do
|
|
75
|
-
memo << name
|
|
76
|
-
end
|
|
77
|
-
end
|
|
78
|
-
end
|
|
79
|
-
|
|
80
|
-
### Private APIs
|
|
81
|
-
def self.default_error_handler(ex, ctx)
|
|
82
|
-
logger.warn(dump_json(ctx)) unless ctx.empty?
|
|
83
|
-
logger.warn("#{ex.class.name}: #{ex.message}")
|
|
84
|
-
logger.warn(ex.backtrace.join("\n")) unless ex.backtrace.nil?
|
|
85
|
-
end
|
|
86
|
-
|
|
87
|
-
@config = DEFAULTS.dup
|
|
88
|
-
def self.options
|
|
89
|
-
logger.warn "`config.options[:key] = value` is deprecated, use `config[:key] = value`: #{caller(1..2)}"
|
|
90
|
-
@config
|
|
91
|
-
end
|
|
92
|
-
|
|
93
|
-
def self.options=(opts)
|
|
94
|
-
logger.warn "config.options = hash` is deprecated, use `config.merge!(hash)`: #{caller(1..2)}"
|
|
95
|
-
@config = opts
|
|
96
|
-
end
|
|
97
|
-
|
|
98
|
-
def self.[](key)
|
|
99
|
-
@config[key]
|
|
100
|
-
end
|
|
101
|
-
|
|
102
|
-
def self.[]=(key, val)
|
|
103
|
-
@config[key] = val
|
|
104
|
-
end
|
|
105
|
-
|
|
106
|
-
def self.merge!(hash)
|
|
107
|
-
@config.merge!(hash)
|
|
108
|
-
end
|
|
109
|
-
|
|
110
|
-
def self.fetch(*args, &block)
|
|
111
|
-
@config.fetch(*args, &block)
|
|
112
|
-
end
|
|
113
|
-
|
|
114
|
-
def self.handle_exception(ex, ctx = {})
|
|
115
|
-
self[:error_handlers].each do |handler|
|
|
116
|
-
handler.call(ex, ctx)
|
|
117
|
-
rescue => ex
|
|
118
|
-
logger.error "!!! ERROR HANDLER THREW AN ERROR !!!"
|
|
119
|
-
logger.error ex
|
|
120
|
-
logger.error ex.backtrace.join("\n") unless ex.backtrace.nil?
|
|
121
|
-
end
|
|
122
|
-
end
|
|
123
|
-
###
|
|
124
|
-
|
|
125
|
-
##
|
|
126
|
-
# Configuration for Sidekiq server, use like:
|
|
127
|
-
#
|
|
128
|
-
# Sidekiq.configure_server do |config|
|
|
129
|
-
# config.server_middleware do |chain|
|
|
130
|
-
# chain.add MyServerHook
|
|
131
|
-
# end
|
|
132
|
-
# end
|
|
133
|
-
def self.configure_server
|
|
134
|
-
yield self if server?
|
|
135
|
-
end
|
|
136
|
-
|
|
137
|
-
##
|
|
138
|
-
# Configuration for Sidekiq client, use like:
|
|
139
|
-
#
|
|
140
|
-
# Sidekiq.configure_client do |config|
|
|
141
|
-
# config.redis = { size: 1, url: 'redis://myhost:8877/0' }
|
|
142
|
-
# end
|
|
143
|
-
def self.configure_client
|
|
144
|
-
yield self unless server?
|
|
45
|
+
puts "Take a deep breath and count to ten..."
|
|
145
46
|
end
|
|
146
47
|
|
|
147
48
|
def self.server?
|
|
148
49
|
defined?(Sidekiq::CLI)
|
|
149
50
|
end
|
|
150
51
|
|
|
151
|
-
def self.
|
|
152
|
-
|
|
153
|
-
redis_pool.with do |conn|
|
|
154
|
-
retryable = true
|
|
155
|
-
begin
|
|
156
|
-
yield conn
|
|
157
|
-
rescue RedisConnection.adapter::BaseError => ex
|
|
158
|
-
# 2550 Failover can cause the server to become a replica, need
|
|
159
|
-
# to disconnect and reopen the socket to get back to the primary.
|
|
160
|
-
# 4495 Use the same logic if we have a "Not enough replicas" error from the primary
|
|
161
|
-
# 4985 Use the same logic when a blocking command is force-unblocked
|
|
162
|
-
# The same retry logic is also used in client.rb
|
|
163
|
-
if retryable && ex.message =~ /READONLY|NOREPLICAS|UNBLOCKED/
|
|
164
|
-
conn.disconnect!
|
|
165
|
-
retryable = false
|
|
166
|
-
retry
|
|
167
|
-
end
|
|
168
|
-
raise
|
|
169
|
-
end
|
|
170
|
-
end
|
|
171
|
-
end
|
|
172
|
-
|
|
173
|
-
def self.redis_info
|
|
174
|
-
redis do |conn|
|
|
175
|
-
# admin commands can't go through redis-namespace starting
|
|
176
|
-
# in redis-namespace 2.0
|
|
177
|
-
if conn.respond_to?(:namespace)
|
|
178
|
-
conn.redis.info
|
|
179
|
-
else
|
|
180
|
-
conn.info
|
|
181
|
-
end
|
|
182
|
-
rescue RedisConnection.adapter::CommandError => ex
|
|
183
|
-
# 2850 return fake version when INFO command has (probably) been renamed
|
|
184
|
-
raise unless /unknown command/.match?(ex.message)
|
|
185
|
-
FAKE_INFO
|
|
186
|
-
end
|
|
52
|
+
def self.load_json(string)
|
|
53
|
+
JSON.parse(string)
|
|
187
54
|
end
|
|
188
55
|
|
|
189
|
-
def self.
|
|
190
|
-
|
|
56
|
+
def self.dump_json(object)
|
|
57
|
+
JSON.generate(object)
|
|
191
58
|
end
|
|
192
59
|
|
|
193
|
-
def self.
|
|
194
|
-
|
|
195
|
-
hash
|
|
196
|
-
else
|
|
197
|
-
RedisConnection.create(hash)
|
|
198
|
-
end
|
|
60
|
+
def self.pro?
|
|
61
|
+
defined?(Sidekiq::Pro)
|
|
199
62
|
end
|
|
200
63
|
|
|
201
|
-
def self.
|
|
202
|
-
|
|
203
|
-
yield @client_chain if block_given?
|
|
204
|
-
@client_chain
|
|
64
|
+
def self.ent?
|
|
65
|
+
defined?(Sidekiq::Enterprise)
|
|
205
66
|
end
|
|
206
67
|
|
|
207
|
-
def self.
|
|
208
|
-
|
|
209
|
-
yield @server_chain if block_given?
|
|
210
|
-
@server_chain
|
|
68
|
+
def self.redis_pool
|
|
69
|
+
(Thread.current[:sidekiq_capsule] || default_configuration).redis_pool
|
|
211
70
|
end
|
|
212
71
|
|
|
213
|
-
def self.
|
|
214
|
-
|
|
72
|
+
def self.redis(&block)
|
|
73
|
+
(Thread.current[:sidekiq_capsule] || default_configuration).redis(&block)
|
|
215
74
|
end
|
|
216
75
|
|
|
217
|
-
def self.
|
|
218
|
-
|
|
76
|
+
def self.strict_args!(mode = :raise)
|
|
77
|
+
Sidekiq::Config::DEFAULTS[:on_complex_arguments] = mode
|
|
219
78
|
end
|
|
220
79
|
|
|
221
80
|
def self.default_job_options=(hash)
|
|
222
81
|
@default_job_options = default_job_options.merge(hash.transform_keys(&:to_s))
|
|
223
82
|
end
|
|
224
83
|
|
|
225
|
-
def self.default_worker_options # deprecated
|
|
226
|
-
@default_job_options ||= {"retry" => true, "queue" => "default"}
|
|
227
|
-
end
|
|
228
|
-
|
|
229
84
|
def self.default_job_options
|
|
230
85
|
@default_job_options ||= {"retry" => true, "queue" => "default"}
|
|
231
86
|
end
|
|
232
87
|
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
# the job dies. It's the notification to your application
|
|
236
|
-
# that this job will not succeed without manual intervention.
|
|
237
|
-
#
|
|
238
|
-
# Sidekiq.configure_server do |config|
|
|
239
|
-
# config.death_handlers << ->(job, ex) do
|
|
240
|
-
# end
|
|
241
|
-
# end
|
|
242
|
-
def self.death_handlers
|
|
243
|
-
self[:death_handlers]
|
|
244
|
-
end
|
|
245
|
-
|
|
246
|
-
def self.load_json(string)
|
|
247
|
-
JSON.parse(string)
|
|
248
|
-
end
|
|
249
|
-
|
|
250
|
-
def self.dump_json(object)
|
|
251
|
-
JSON.generate(object)
|
|
252
|
-
end
|
|
253
|
-
|
|
254
|
-
def self.log_formatter
|
|
255
|
-
@log_formatter ||= if ENV["DYNO"]
|
|
256
|
-
Sidekiq::Logger::Formatters::WithoutTimestamp.new
|
|
257
|
-
else
|
|
258
|
-
Sidekiq::Logger::Formatters::Pretty.new
|
|
259
|
-
end
|
|
260
|
-
end
|
|
261
|
-
|
|
262
|
-
def self.log_formatter=(log_formatter)
|
|
263
|
-
@log_formatter = log_formatter
|
|
264
|
-
logger.formatter = log_formatter
|
|
88
|
+
def self.default_configuration
|
|
89
|
+
@config ||= Sidekiq::Config.new
|
|
265
90
|
end
|
|
266
91
|
|
|
267
92
|
def self.logger
|
|
268
|
-
|
|
269
|
-
end
|
|
270
|
-
|
|
271
|
-
def self.logger=(logger)
|
|
272
|
-
if logger.nil?
|
|
273
|
-
self.logger.level = Logger::FATAL
|
|
274
|
-
return self.logger
|
|
275
|
-
end
|
|
276
|
-
|
|
277
|
-
logger.extend(Sidekiq::LoggingUtils)
|
|
278
|
-
|
|
279
|
-
@logger = logger
|
|
280
|
-
end
|
|
281
|
-
|
|
282
|
-
def self.pro?
|
|
283
|
-
defined?(Sidekiq::Pro)
|
|
93
|
+
default_configuration.logger
|
|
284
94
|
end
|
|
285
95
|
|
|
286
|
-
def self.
|
|
287
|
-
|
|
96
|
+
def self.configure_server(&block)
|
|
97
|
+
(@config_blocks ||= []) << block
|
|
98
|
+
yield default_configuration if server?
|
|
288
99
|
end
|
|
289
100
|
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
#
|
|
294
|
-
# See sidekiq/scheduled.rb for an in-depth explanation of this value
|
|
295
|
-
def self.average_scheduled_poll_interval=(interval)
|
|
296
|
-
self[:average_scheduled_poll_interval] = interval
|
|
101
|
+
def self.freeze!
|
|
102
|
+
@frozen = true
|
|
103
|
+
@config_blocks = nil
|
|
297
104
|
end
|
|
298
105
|
|
|
299
|
-
#
|
|
106
|
+
# Creates a Sidekiq::Config instance that is more tuned for embedding
|
|
107
|
+
# within an arbitrary Ruby process. Notably it reduces concurrency by
|
|
108
|
+
# default so there is less contention for CPU time with other threads.
|
|
300
109
|
#
|
|
301
|
-
# Sidekiq.
|
|
302
|
-
# config.
|
|
110
|
+
# inst = Sidekiq.configure_embed do |config|
|
|
111
|
+
# config.queues = %w[critical default low]
|
|
303
112
|
# end
|
|
113
|
+
# inst.run
|
|
114
|
+
# sleep 10
|
|
115
|
+
# inst.terminate
|
|
304
116
|
#
|
|
305
|
-
#
|
|
306
|
-
|
|
307
|
-
self[:error_handlers]
|
|
308
|
-
end
|
|
309
|
-
|
|
310
|
-
# Register a block to run at a point in the Sidekiq lifecycle.
|
|
311
|
-
# :startup, :quiet or :shutdown are valid events.
|
|
117
|
+
# NB: it is really easy to overload a Ruby process with threads due to the GIL.
|
|
118
|
+
# I do not recommend setting concurrency higher than 2-3.
|
|
312
119
|
#
|
|
313
|
-
#
|
|
314
|
-
#
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
120
|
+
# NB: Sidekiq only supports one instance in memory. You will get undefined behavior
|
|
121
|
+
# if you try to embed Sidekiq twice in the same process.
|
|
122
|
+
def self.configure_embed(&block)
|
|
123
|
+
raise "Sidekiq global configuration is frozen, you must create all embedded instances BEFORE calling `run`" if @frozen
|
|
124
|
+
|
|
125
|
+
require "sidekiq/embedded"
|
|
126
|
+
cfg = default_configuration
|
|
127
|
+
cfg.concurrency = 2
|
|
128
|
+
@config_blocks&.each { |block| block.call(cfg) }
|
|
129
|
+
yield cfg
|
|
130
|
+
|
|
131
|
+
Sidekiq::Embedded.new(cfg)
|
|
322
132
|
end
|
|
323
133
|
|
|
324
|
-
def self.
|
|
325
|
-
|
|
134
|
+
def self.configure_client
|
|
135
|
+
yield default_configuration unless server?
|
|
326
136
|
end
|
|
327
137
|
|
|
328
138
|
# We are shutting down Sidekiq but what about threads that
|
data/sidekiq.gemspec
CHANGED
|
@@ -2,27 +2,38 @@ require_relative "lib/sidekiq/version"
|
|
|
2
2
|
|
|
3
3
|
Gem::Specification.new do |gem|
|
|
4
4
|
gem.authors = ["Mike Perham"]
|
|
5
|
-
gem.email = ["
|
|
5
|
+
gem.email = ["info@contribsys.com"]
|
|
6
6
|
gem.summary = "Simple, efficient background processing for Ruby"
|
|
7
7
|
gem.description = "Simple, efficient background processing for Ruby."
|
|
8
8
|
gem.homepage = "https://sidekiq.org"
|
|
9
9
|
gem.license = "LGPL-3.0"
|
|
10
10
|
|
|
11
11
|
gem.executables = ["sidekiq", "sidekiqmon"]
|
|
12
|
-
gem.files = [
|
|
12
|
+
gem.files = %w[sidekiq.gemspec README.md Changes.md LICENSE.txt] + `git ls-files | grep -E '^(bin|lib|web)'`.split("\n")
|
|
13
13
|
gem.name = "sidekiq"
|
|
14
14
|
gem.version = Sidekiq::VERSION
|
|
15
|
-
gem.required_ruby_version = ">= 2.
|
|
15
|
+
gem.required_ruby_version = ">= 2.7.0"
|
|
16
16
|
|
|
17
17
|
gem.metadata = {
|
|
18
18
|
"homepage_uri" => "https://sidekiq.org",
|
|
19
|
-
"bug_tracker_uri" => "https://github.com/
|
|
20
|
-
"documentation_uri" => "https://github.com/
|
|
21
|
-
"changelog_uri" => "https://github.com/
|
|
22
|
-
"source_code_uri" => "https://github.com/
|
|
19
|
+
"bug_tracker_uri" => "https://github.com/sidekiq/sidekiq/issues",
|
|
20
|
+
"documentation_uri" => "https://github.com/sidekiq/sidekiq/wiki",
|
|
21
|
+
"changelog_uri" => "https://github.com/sidekiq/sidekiq/blob/main/Changes.md",
|
|
22
|
+
"source_code_uri" => "https://github.com/sidekiq/sidekiq",
|
|
23
|
+
"rubygems_mfa_required" => "true"
|
|
23
24
|
}
|
|
24
25
|
|
|
25
|
-
gem.add_dependency "redis", ">=
|
|
26
|
-
gem.add_dependency "connection_pool", ">= 2.
|
|
27
|
-
gem.add_dependency "rack", "
|
|
26
|
+
gem.add_dependency "redis-client", ">= 0.11.0"
|
|
27
|
+
gem.add_dependency "connection_pool", ">= 2.3.0"
|
|
28
|
+
gem.add_dependency "rack", ">= 2.2.4"
|
|
29
|
+
gem.add_dependency "concurrent-ruby", "< 2"
|
|
30
|
+
gem.post_install_message = <<~EOM
|
|
31
|
+
|
|
32
|
+
Welcome to Sidekiq 7.0!
|
|
33
|
+
|
|
34
|
+
1. Use `gem 'sidekiq', '<7'` in your Gemfile if you don't want this new version.
|
|
35
|
+
2. Read the release notes at https://github.com/sidekiq/sidekiq/blob/main/docs/7.0-Upgrade.md
|
|
36
|
+
3. If you have problems, search for open/closed issues at https://github.com/sidekiq/sidekiq/issues/
|
|
37
|
+
|
|
38
|
+
EOM
|
|
28
39
|
end
|
|
@@ -31,6 +31,7 @@ function addListeners() {
|
|
|
31
31
|
node.addEventListener("click", addDataToggleListeners)
|
|
32
32
|
})
|
|
33
33
|
|
|
34
|
+
addShiftClickListeners()
|
|
34
35
|
updateFuzzyTimes();
|
|
35
36
|
setLivePollFromUrl();
|
|
36
37
|
|
|
@@ -63,7 +64,7 @@ function addPollingListeners(_event) {
|
|
|
63
64
|
function addDataToggleListeners(event) {
|
|
64
65
|
var source = event.target || event.srcElement;
|
|
65
66
|
var targName = source.getAttribute("data-toggle");
|
|
66
|
-
var full = document.getElementById(targName
|
|
67
|
+
var full = document.getElementById(targName);
|
|
67
68
|
if (full.style.display == "block") {
|
|
68
69
|
full.style.display = 'none';
|
|
69
70
|
} else {
|
|
@@ -71,6 +72,23 @@ function addDataToggleListeners(event) {
|
|
|
71
72
|
}
|
|
72
73
|
}
|
|
73
74
|
|
|
75
|
+
function addShiftClickListeners() {
|
|
76
|
+
let checkboxes = Array.from(document.querySelectorAll(".shift_clickable"));
|
|
77
|
+
let lastChecked = null;
|
|
78
|
+
checkboxes.forEach(checkbox => {
|
|
79
|
+
checkbox.addEventListener("click", (e) => {
|
|
80
|
+
if (e.shiftKey && lastChecked) {
|
|
81
|
+
let myIndex = checkboxes.indexOf(checkbox);
|
|
82
|
+
let lastIndex = checkboxes.indexOf(lastChecked);
|
|
83
|
+
let [min, max] = [myIndex, lastIndex].sort();
|
|
84
|
+
let newState = checkbox.checked;
|
|
85
|
+
checkboxes.slice(min, max).forEach(c => c.checked = newState);
|
|
86
|
+
}
|
|
87
|
+
lastChecked = checkbox;
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
|
|
74
92
|
function updateFuzzyTimes() {
|
|
75
93
|
var locale = document.body.getAttribute("data-locale");
|
|
76
94
|
var parts = locale.split('-');
|