sidekiq 6.5.12 → 7.0.6
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 +63 -22
- 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 +84 -121
- data/lib/sidekiq/capsule.rb +127 -0
- data/lib/sidekiq/cli.rb +55 -74
- data/lib/sidekiq/client.rb +29 -16
- data/lib/sidekiq/component.rb +3 -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 +11 -14
- data/lib/sidekiq/job.rb +375 -10
- data/lib/sidekiq/job_logger.rb +2 -2
- data/lib/sidekiq/job_retry.rb +9 -9
- data/lib/sidekiq/job_util.rb +48 -14
- data/lib/sidekiq/launcher.rb +64 -61
- 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 +20 -18
- data/lib/sidekiq/middleware/chain.rb +19 -18
- data/lib/sidekiq/middleware/current_attributes.rb +8 -15
- data/lib/sidekiq/monitor.rb +16 -3
- data/lib/sidekiq/processor.rb +21 -27
- data/lib/sidekiq/rails.rb +13 -17
- data/lib/sidekiq/redis_client_adapter.rb +8 -47
- data/lib/sidekiq/redis_connection.rb +11 -111
- data/lib/sidekiq/scheduled.rb +20 -21
- 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/application.rb +21 -6
- data/lib/sidekiq/web/csrf_protection.rb +1 -1
- data/lib/sidekiq/web/helpers.rb +16 -15
- data/lib/sidekiq/web.rb +6 -17
- data/lib/sidekiq/worker_compatibility_alias.rb +13 -0
- data/lib/sidekiq.rb +76 -274
- data/sidekiq.gemspec +20 -10
- data/web/assets/javascripts/application.js +18 -1
- 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 +117 -115
- data/web/assets/stylesheets/application-dark.css +4 -0
- data/web/assets/stylesheets/application-rtl.css +2 -91
- data/web/assets/stylesheets/application.css +23 -298
- 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 +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 +64 -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 +20 -18
- data/web/locales/zh-tw.yml +10 -1
- 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/_paging.erb +2 -0
- data/web/views/_poll_link.erb +1 -1
- data/web/views/busy.erb +37 -26
- data/web/views/dashboard.erb +36 -5
- data/web/views/metrics.erb +33 -20
- data/web/views/metrics_for_job.erb +22 -38
- data/web/views/morgue.erb +5 -9
- data/web/views/queue.erb +10 -14
- data/web/views/queues.erb +3 -1
- data/web/views/retries.erb +5 -9
- data/web/views/scheduled.erb +12 -13
- metadata +50 -40
- 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 -370
- data/web/assets/javascripts/graph.js +0 -16
- /data/{LICENSE → LICENSE.txt} +0 -0
@@ -20,6 +20,12 @@ module Sidekiq
|
|
20
20
|
"worker-src 'self'",
|
21
21
|
"base-uri 'self'"
|
22
22
|
].join("; ").freeze
|
23
|
+
METRICS_PERIODS = {
|
24
|
+
"1h" => 60,
|
25
|
+
"2h" => 120,
|
26
|
+
"4h" => 240,
|
27
|
+
"8h" => 480
|
28
|
+
}
|
23
29
|
|
24
30
|
def initialize(klass)
|
25
31
|
@klass = klass
|
@@ -62,14 +68,20 @@ module Sidekiq
|
|
62
68
|
|
63
69
|
get "/metrics" do
|
64
70
|
q = Sidekiq::Metrics::Query.new
|
65
|
-
@
|
71
|
+
@period = params[:period]
|
72
|
+
@periods = METRICS_PERIODS
|
73
|
+
minutes = @periods.fetch(@period, @periods.values.first)
|
74
|
+
@query_result = q.top_jobs(minutes: minutes)
|
66
75
|
erb(:metrics)
|
67
76
|
end
|
68
77
|
|
69
78
|
get "/metrics/:name" do
|
70
79
|
@name = route_params[:name]
|
80
|
+
@period = params[:period]
|
71
81
|
q = Sidekiq::Metrics::Query.new
|
72
|
-
@
|
82
|
+
@periods = METRICS_PERIODS
|
83
|
+
minutes = @periods.fetch(@period, @periods.values.first)
|
84
|
+
@query_result = q.for_job(@name, minutes: minutes)
|
73
85
|
erb(:metrics_for_job)
|
74
86
|
end
|
75
87
|
|
@@ -82,11 +94,14 @@ module Sidekiq
|
|
82
94
|
|
83
95
|
post "/busy" do
|
84
96
|
if params["identity"]
|
85
|
-
|
86
|
-
|
87
|
-
|
97
|
+
pro = Sidekiq::ProcessSet[params["identity"]]
|
98
|
+
|
99
|
+
pro.quiet! if params["quiet"]
|
100
|
+
pro.stop! if params["stop"]
|
88
101
|
else
|
89
102
|
processes.each do |pro|
|
103
|
+
next if pro.embedded?
|
104
|
+
|
90
105
|
pro.quiet! if params["quiet"]
|
91
106
|
pro.stop! if params["stop"]
|
92
107
|
end
|
@@ -310,7 +325,7 @@ module Sidekiq
|
|
310
325
|
end
|
311
326
|
|
312
327
|
get "/stats/queues" do
|
313
|
-
json Sidekiq::Stats
|
328
|
+
json Sidekiq::Stats.new.queues
|
314
329
|
end
|
315
330
|
|
316
331
|
def call(env)
|
@@ -152,7 +152,7 @@ module Sidekiq
|
|
152
152
|
# value and decrypt it
|
153
153
|
token_length = masked_token.length / 2
|
154
154
|
one_time_pad = masked_token[0...token_length]
|
155
|
-
encrypted_token = masked_token[token_length
|
155
|
+
encrypted_token = masked_token[token_length..]
|
156
156
|
xor_byte_strings(one_time_pad, encrypted_token)
|
157
157
|
end
|
158
158
|
|
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.safe_load(File.
|
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
|
@@ -161,22 +161,26 @@ module Sidekiq
|
|
161
161
|
end
|
162
162
|
end
|
163
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
|
+
|
164
172
|
def stats
|
165
173
|
@stats ||= Sidekiq::Stats.new
|
166
174
|
end
|
167
175
|
|
168
|
-
def
|
176
|
+
def redis_url
|
169
177
|
Sidekiq.redis do |conn|
|
170
|
-
conn.
|
178
|
+
conn.config.server_url
|
171
179
|
end
|
172
180
|
end
|
173
181
|
|
174
|
-
def namespace
|
175
|
-
@ns ||= Sidekiq.redis { |conn| conn.respond_to?(:namespace) ? conn.namespace : nil }
|
176
|
-
end
|
177
|
-
|
178
182
|
def redis_info
|
179
|
-
Sidekiq.redis_info
|
183
|
+
Sidekiq.default_configuration.redis_info
|
180
184
|
end
|
181
185
|
|
182
186
|
def root_path
|
@@ -314,7 +318,7 @@ module Sidekiq
|
|
314
318
|
end
|
315
319
|
|
316
320
|
def environment_title_prefix
|
317
|
-
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"
|
318
322
|
|
319
323
|
"[#{environment.upcase}] " unless environment == "production"
|
320
324
|
end
|
@@ -327,11 +331,8 @@ module Sidekiq
|
|
327
331
|
Time.now.utc.strftime("%H:%M:%S UTC")
|
328
332
|
end
|
329
333
|
|
330
|
-
def
|
331
|
-
|
332
|
-
namespace_suffix = namespace.nil? ? "" : "##{namespace}"
|
333
|
-
"#{redis_connection}#{namespace_suffix}"
|
334
|
-
end
|
334
|
+
def pollable?
|
335
|
+
!(current_path == "" || current_path.start_with?("metrics"))
|
335
336
|
end
|
336
337
|
|
337
338
|
def retry_or_delete_or_kill(job, params)
|
data/lib/sidekiq/web.rb
CHANGED
@@ -30,13 +30,10 @@ 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
|
-
if ENV["SIDEKIQ_METRICS_BETA"] == "1"
|
37
|
-
DEFAULT_TABS["Metrics"] = "metrics"
|
38
|
-
end
|
39
|
-
|
40
37
|
class << self
|
41
38
|
def settings
|
42
39
|
self
|
@@ -51,6 +48,10 @@ module Sidekiq
|
|
51
48
|
end
|
52
49
|
alias_method :tabs, :custom_tabs
|
53
50
|
|
51
|
+
def custom_job_info_rows
|
52
|
+
@custom_job_info_rows ||= []
|
53
|
+
end
|
54
|
+
|
54
55
|
def locales
|
55
56
|
@locales ||= LOCALES
|
56
57
|
end
|
@@ -79,14 +80,6 @@ module Sidekiq
|
|
79
80
|
send(:"#{attribute}=", value)
|
80
81
|
end
|
81
82
|
|
82
|
-
def sessions=(val)
|
83
|
-
puts "WARNING: Sidekiq::Web.sessions= is no longer relevant and will be removed in Sidekiq 7.0. #{caller(1..1).first}"
|
84
|
-
end
|
85
|
-
|
86
|
-
def session_secret=(val)
|
87
|
-
puts "WARNING: Sidekiq::Web.session_secret= is no longer relevant and will be removed in Sidekiq 7.0. #{caller(1..1).first}"
|
88
|
-
end
|
89
|
-
|
90
83
|
attr_accessor :app_url, :redis_pool
|
91
84
|
attr_writer :locales, :views
|
92
85
|
end
|
@@ -133,10 +126,6 @@ module Sidekiq
|
|
133
126
|
send(:"#{attribute}=", value)
|
134
127
|
end
|
135
128
|
|
136
|
-
def sessions=(val)
|
137
|
-
puts "Sidekiq::Web#sessions= is no longer relevant and will be removed in Sidekiq 7.0. #{caller[2..2].first}"
|
138
|
-
end
|
139
|
-
|
140
129
|
def self.register(extension)
|
141
130
|
extension.registered(WebApplication)
|
142
131
|
end
|
@@ -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,320 +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
|
-
# triggers when we fire the first heartbeat on startup OR repairing a network partition
|
38
|
-
heartbeat: [],
|
39
|
-
# triggers on EVERY heartbeat call, every 10 seconds
|
40
|
-
beat: []
|
41
|
-
},
|
42
|
-
dead_max_jobs: 10_000,
|
43
|
-
dead_timeout_in_seconds: 180 * 24 * 60 * 60, # 6 months
|
44
|
-
reloader: proc { |&block| block.call }
|
45
|
-
}
|
46
|
-
|
47
|
-
FAKE_INFO = {
|
48
|
-
"redis_version" => "9.9.9",
|
49
|
-
"uptime_in_days" => "9999",
|
50
|
-
"connected_clients" => "9999",
|
51
|
-
"used_memory_human" => "9P",
|
52
|
-
"used_memory_peak_human" => "9P"
|
53
|
-
}
|
54
|
-
|
55
44
|
def self.❨╯°□°❩╯︵┻━┻
|
56
|
-
puts "
|
57
|
-
end
|
58
|
-
|
59
|
-
# config.concurrency = 5
|
60
|
-
def self.concurrency=(val)
|
61
|
-
self[:concurrency] = Integer(val)
|
62
|
-
end
|
63
|
-
|
64
|
-
# config.queues = %w( high default low ) # strict
|
65
|
-
# config.queues = %w( high,3 default,2 low,1 ) # weighted
|
66
|
-
# config.queues = %w( feature1,1 feature2,1 feature3,1 ) # random
|
67
|
-
#
|
68
|
-
# With weighted priority, queue will be checked first (weight / total) of the time.
|
69
|
-
# high will be checked first (3/6) or 50% of the time.
|
70
|
-
# I'd recommend setting weights between 1-10. Weights in the hundreds or thousands
|
71
|
-
# are ridiculous and unnecessarily expensive. You can get random queue ordering
|
72
|
-
# by explicitly setting all weights to 1.
|
73
|
-
def self.queues=(val)
|
74
|
-
self[:queues] = Array(val).each_with_object([]) do |qstr, memo|
|
75
|
-
name, weight = qstr.split(",")
|
76
|
-
self[:strict] = false if weight.to_i > 0
|
77
|
-
[weight.to_i, 1].max.times do
|
78
|
-
memo << name
|
79
|
-
end
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
|
-
### Private APIs
|
84
|
-
def self.default_error_handler(ex, ctx)
|
85
|
-
logger.warn(dump_json(ctx)) unless ctx.empty?
|
86
|
-
logger.warn("#{ex.class.name}: #{ex.message}")
|
87
|
-
logger.warn(ex.backtrace.join("\n")) unless ex.backtrace.nil?
|
88
|
-
end
|
89
|
-
|
90
|
-
# DEFAULT_ERROR_HANDLER is a constant that allows the default error handler to
|
91
|
-
# be referenced. It must be defined here, after the default_error_handler
|
92
|
-
# method is defined.
|
93
|
-
DEFAULT_ERROR_HANDLER = method(:default_error_handler)
|
94
|
-
|
95
|
-
@config = DEFAULTS.dup
|
96
|
-
def self.options
|
97
|
-
logger.warn "`config.options[:key] = value` is deprecated, use `config[:key] = value`: #{caller(1..2)}"
|
98
|
-
@config
|
99
|
-
end
|
100
|
-
|
101
|
-
def self.options=(opts)
|
102
|
-
logger.warn "config.options = hash` is deprecated, use `config.merge!(hash)`: #{caller(1..2)}"
|
103
|
-
@config = opts
|
104
|
-
end
|
105
|
-
|
106
|
-
def self.[](key)
|
107
|
-
@config[key]
|
108
|
-
end
|
109
|
-
|
110
|
-
def self.[]=(key, val)
|
111
|
-
@config[key] = val
|
112
|
-
end
|
113
|
-
|
114
|
-
def self.merge!(hash)
|
115
|
-
@config.merge!(hash)
|
116
|
-
end
|
117
|
-
|
118
|
-
def self.fetch(*args, &block)
|
119
|
-
@config.fetch(*args, &block)
|
120
|
-
end
|
121
|
-
|
122
|
-
def self.handle_exception(ex, ctx = {})
|
123
|
-
self[:error_handlers].each do |handler|
|
124
|
-
handler.call(ex, ctx)
|
125
|
-
rescue => ex
|
126
|
-
logger.error "!!! ERROR HANDLER THREW AN ERROR !!!"
|
127
|
-
logger.error ex
|
128
|
-
logger.error ex.backtrace.join("\n") unless ex.backtrace.nil?
|
129
|
-
end
|
130
|
-
end
|
131
|
-
###
|
132
|
-
|
133
|
-
##
|
134
|
-
# Configuration for Sidekiq server, use like:
|
135
|
-
#
|
136
|
-
# Sidekiq.configure_server do |config|
|
137
|
-
# config.server_middleware do |chain|
|
138
|
-
# chain.add MyServerHook
|
139
|
-
# end
|
140
|
-
# end
|
141
|
-
def self.configure_server
|
142
|
-
yield self if server?
|
143
|
-
end
|
144
|
-
|
145
|
-
##
|
146
|
-
# Configuration for Sidekiq client, use like:
|
147
|
-
#
|
148
|
-
# Sidekiq.configure_client do |config|
|
149
|
-
# config.redis = { size: 1, url: 'redis://myhost:8877/0' }
|
150
|
-
# end
|
151
|
-
def self.configure_client
|
152
|
-
yield self unless server?
|
45
|
+
puts "Take a deep breath and count to ten..."
|
153
46
|
end
|
154
47
|
|
155
48
|
def self.server?
|
156
49
|
defined?(Sidekiq::CLI)
|
157
50
|
end
|
158
51
|
|
159
|
-
def self.
|
160
|
-
|
161
|
-
redis_pool.with do |conn|
|
162
|
-
retryable = true
|
163
|
-
begin
|
164
|
-
yield conn
|
165
|
-
rescue RedisConnection.adapter::BaseError => ex
|
166
|
-
# 2550 Failover can cause the server to become a replica, need
|
167
|
-
# to disconnect and reopen the socket to get back to the primary.
|
168
|
-
# 4495 Use the same logic if we have a "Not enough replicas" error from the primary
|
169
|
-
# 4985 Use the same logic when a blocking command is force-unblocked
|
170
|
-
# The same retry logic is also used in client.rb
|
171
|
-
if retryable && ex.message =~ /READONLY|NOREPLICAS|UNBLOCKED/
|
172
|
-
conn.disconnect!
|
173
|
-
retryable = false
|
174
|
-
retry
|
175
|
-
end
|
176
|
-
raise
|
177
|
-
end
|
178
|
-
end
|
179
|
-
end
|
180
|
-
|
181
|
-
def self.redis_info
|
182
|
-
redis do |conn|
|
183
|
-
# admin commands can't go through redis-namespace starting
|
184
|
-
# in redis-namespace 2.0
|
185
|
-
if conn.respond_to?(:namespace)
|
186
|
-
conn.redis.info
|
187
|
-
else
|
188
|
-
conn.info
|
189
|
-
end
|
190
|
-
rescue RedisConnection.adapter::CommandError => ex
|
191
|
-
# 2850 return fake version when INFO command has (probably) been renamed
|
192
|
-
raise unless /unknown command/.match?(ex.message)
|
193
|
-
FAKE_INFO
|
194
|
-
end
|
52
|
+
def self.load_json(string)
|
53
|
+
JSON.parse(string)
|
195
54
|
end
|
196
55
|
|
197
|
-
def self.
|
198
|
-
|
56
|
+
def self.dump_json(object)
|
57
|
+
JSON.generate(object)
|
199
58
|
end
|
200
59
|
|
201
|
-
def self.
|
202
|
-
|
203
|
-
hash
|
204
|
-
else
|
205
|
-
RedisConnection.create(hash)
|
206
|
-
end
|
60
|
+
def self.pro?
|
61
|
+
defined?(Sidekiq::Pro)
|
207
62
|
end
|
208
63
|
|
209
|
-
def self.
|
210
|
-
|
211
|
-
yield @client_chain if block_given?
|
212
|
-
@client_chain
|
64
|
+
def self.ent?
|
65
|
+
defined?(Sidekiq::Enterprise)
|
213
66
|
end
|
214
67
|
|
215
|
-
def self.
|
216
|
-
|
217
|
-
yield @server_chain if block_given?
|
218
|
-
@server_chain
|
68
|
+
def self.redis_pool
|
69
|
+
(Thread.current[:sidekiq_capsule] || default_configuration).redis_pool
|
219
70
|
end
|
220
71
|
|
221
|
-
def self.
|
222
|
-
|
72
|
+
def self.redis(&block)
|
73
|
+
(Thread.current[:sidekiq_capsule] || default_configuration).redis(&block)
|
223
74
|
end
|
224
75
|
|
225
|
-
def self.
|
226
|
-
|
76
|
+
def self.strict_args!(mode = :raise)
|
77
|
+
Sidekiq::Config::DEFAULTS[:on_complex_arguments] = mode
|
227
78
|
end
|
228
79
|
|
229
80
|
def self.default_job_options=(hash)
|
230
81
|
@default_job_options = default_job_options.merge(hash.transform_keys(&:to_s))
|
231
82
|
end
|
232
83
|
|
233
|
-
def self.default_worker_options # deprecated
|
234
|
-
@default_job_options ||= {"retry" => true, "queue" => "default"}
|
235
|
-
end
|
236
|
-
|
237
84
|
def self.default_job_options
|
238
85
|
@default_job_options ||= {"retry" => true, "queue" => "default"}
|
239
86
|
end
|
240
87
|
|
241
|
-
|
242
|
-
|
243
|
-
# the job dies. It's the notification to your application
|
244
|
-
# that this job will not succeed without manual intervention.
|
245
|
-
#
|
246
|
-
# Sidekiq.configure_server do |config|
|
247
|
-
# config.death_handlers << ->(job, ex) do
|
248
|
-
# end
|
249
|
-
# end
|
250
|
-
def self.death_handlers
|
251
|
-
self[:death_handlers]
|
252
|
-
end
|
253
|
-
|
254
|
-
def self.load_json(string)
|
255
|
-
JSON.parse(string)
|
256
|
-
end
|
257
|
-
|
258
|
-
def self.dump_json(object)
|
259
|
-
JSON.generate(object)
|
260
|
-
end
|
261
|
-
|
262
|
-
def self.log_formatter
|
263
|
-
@log_formatter ||= if ENV["DYNO"]
|
264
|
-
Sidekiq::Logger::Formatters::WithoutTimestamp.new
|
265
|
-
else
|
266
|
-
Sidekiq::Logger::Formatters::Pretty.new
|
267
|
-
end
|
268
|
-
end
|
269
|
-
|
270
|
-
def self.log_formatter=(log_formatter)
|
271
|
-
@log_formatter = log_formatter
|
272
|
-
logger.formatter = log_formatter
|
88
|
+
def self.default_configuration
|
89
|
+
@config ||= Sidekiq::Config.new
|
273
90
|
end
|
274
91
|
|
275
92
|
def self.logger
|
276
|
-
|
277
|
-
end
|
278
|
-
|
279
|
-
def self.logger=(logger)
|
280
|
-
if logger.nil?
|
281
|
-
self.logger.level = Logger::FATAL
|
282
|
-
return self.logger
|
283
|
-
end
|
284
|
-
|
285
|
-
logger.extend(Sidekiq::LoggingUtils)
|
286
|
-
|
287
|
-
@logger = logger
|
288
|
-
end
|
289
|
-
|
290
|
-
def self.pro?
|
291
|
-
defined?(Sidekiq::Pro)
|
93
|
+
default_configuration.logger
|
292
94
|
end
|
293
95
|
|
294
|
-
def self.
|
295
|
-
|
96
|
+
def self.configure_server(&block)
|
97
|
+
(@config_blocks ||= []) << block
|
98
|
+
yield default_configuration if server?
|
296
99
|
end
|
297
100
|
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
#
|
302
|
-
# See sidekiq/scheduled.rb for an in-depth explanation of this value
|
303
|
-
def self.average_scheduled_poll_interval=(interval)
|
304
|
-
self[:average_scheduled_poll_interval] = interval
|
101
|
+
def self.freeze!
|
102
|
+
@frozen = true
|
103
|
+
@config_blocks = nil
|
305
104
|
end
|
306
105
|
|
307
|
-
#
|
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.
|
308
109
|
#
|
309
|
-
# Sidekiq.
|
310
|
-
# config.
|
110
|
+
# inst = Sidekiq.configure_embed do |config|
|
111
|
+
# config.queues = %w[critical default low]
|
311
112
|
# end
|
113
|
+
# inst.run
|
114
|
+
# sleep 10
|
115
|
+
# inst.terminate
|
312
116
|
#
|
313
|
-
#
|
314
|
-
|
315
|
-
self[:error_handlers]
|
316
|
-
end
|
317
|
-
|
318
|
-
# Register a block to run at a point in the Sidekiq lifecycle.
|
319
|
-
# :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.
|
320
119
|
#
|
321
|
-
#
|
322
|
-
#
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
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)
|
330
132
|
end
|
331
133
|
|
332
|
-
def self.
|
333
|
-
|
134
|
+
def self.configure_client
|
135
|
+
yield default_configuration unless server?
|
334
136
|
end
|
335
137
|
|
336
138
|
# We are shutting down Sidekiq but what about threads that
|
data/sidekiq.gemspec
CHANGED
@@ -2,27 +2,37 @@ 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
23
|
}
|
24
24
|
|
25
|
-
gem.add_dependency "redis",
|
26
|
-
gem.add_dependency "connection_pool",
|
27
|
-
gem.add_dependency "rack", "
|
25
|
+
gem.add_dependency "redis-client", ">= 0.11.0"
|
26
|
+
gem.add_dependency "connection_pool", ">= 2.3.0"
|
27
|
+
gem.add_dependency "rack", ">= 2.2.4"
|
28
|
+
gem.add_dependency "concurrent-ruby", "< 2"
|
29
|
+
gem.post_install_message = <<~EOM
|
30
|
+
|
31
|
+
Welcome to Sidekiq 7.0!
|
32
|
+
|
33
|
+
1. Use `gem 'sidekiq', '<7'` in your Gemfile if you don't want this new version.
|
34
|
+
2. Read the release notes at https://github.com/sidekiq/sidekiq/blob/main/docs/7.0-Upgrade.md
|
35
|
+
3. If you have problems, search for open/closed issues at https://github.com/sidekiq/sidekiq/issues/
|
36
|
+
|
37
|
+
EOM
|
28
38
|
end
|