sidekiq 6.4.1 → 7.0.0
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 +107 -5
- data/README.md +14 -13
- data/bin/sidekiq +3 -8
- data/bin/sidekiqload +26 -29
- data/lib/sidekiq/api.rb +232 -157
- data/lib/sidekiq/capsule.rb +110 -0
- data/lib/sidekiq/cli.rb +80 -86
- data/lib/sidekiq/client.rb +54 -42
- data/lib/sidekiq/component.rb +66 -0
- data/lib/sidekiq/config.rb +271 -0
- data/lib/sidekiq/deploy.rb +62 -0
- data/lib/sidekiq/embedded.rb +61 -0
- data/lib/sidekiq/fetch.rb +20 -19
- data/lib/sidekiq/job.rb +375 -10
- data/lib/sidekiq/job_logger.rb +1 -1
- data/lib/sidekiq/job_retry.rb +74 -53
- data/lib/sidekiq/job_util.rb +17 -11
- data/lib/sidekiq/launcher.rb +63 -69
- data/lib/sidekiq/logger.rb +6 -45
- data/lib/sidekiq/manager.rb +33 -32
- data/lib/sidekiq/metrics/query.rb +153 -0
- data/lib/sidekiq/metrics/shared.rb +95 -0
- data/lib/sidekiq/metrics/tracking.rb +134 -0
- data/lib/sidekiq/middleware/chain.rb +84 -42
- data/lib/sidekiq/middleware/current_attributes.rb +18 -17
- data/lib/sidekiq/middleware/i18n.rb +6 -4
- data/lib/sidekiq/middleware/modules.rb +21 -0
- data/lib/sidekiq/monitor.rb +1 -1
- data/lib/sidekiq/paginator.rb +10 -2
- data/lib/sidekiq/processor.rb +56 -59
- data/lib/sidekiq/rails.rb +10 -9
- data/lib/sidekiq/redis_client_adapter.rb +118 -0
- data/lib/sidekiq/redis_connection.rb +13 -82
- data/lib/sidekiq/ring_buffer.rb +29 -0
- data/lib/sidekiq/scheduled.rb +65 -37
- data/lib/sidekiq/testing/inline.rb +4 -4
- data/lib/sidekiq/testing.rb +41 -68
- data/lib/sidekiq/transaction_aware_client.rb +44 -0
- data/lib/sidekiq/version.rb +2 -1
- data/lib/sidekiq/web/action.rb +3 -3
- data/lib/sidekiq/web/application.rb +22 -6
- data/lib/sidekiq/web/csrf_protection.rb +3 -3
- data/lib/sidekiq/web/helpers.rb +21 -19
- data/lib/sidekiq/web.rb +3 -14
- data/lib/sidekiq/worker_compatibility_alias.rb +13 -0
- data/lib/sidekiq.rb +84 -207
- data/sidekiq.gemspec +29 -5
- data/web/assets/javascripts/application.js +58 -26
- 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 +236 -0
- data/web/assets/stylesheets/application-rtl.css +2 -91
- data/web/assets/stylesheets/application.css +64 -297
- 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 +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/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 +63 -55
- 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/_nav.erb +1 -1
- data/web/views/_summary.erb +1 -1
- data/web/views/busy.erb +9 -4
- data/web/views/dashboard.erb +36 -4
- data/web/views/metrics.erb +80 -0
- data/web/views/metrics_for_job.erb +69 -0
- data/web/views/queue.erb +5 -1
- metadata +69 -22
- data/lib/sidekiq/delay.rb +0 -43
- data/lib/sidekiq/exception_handler.rb +0 -27
- 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/util.rb +0 -108
- data/lib/sidekiq/worker.rb +0 -362
- /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.open(file))
|
19
19
|
global.merge!(strs[lang])
|
20
20
|
end
|
21
21
|
end
|
@@ -140,30 +140,39 @@ module Sidekiq
|
|
140
140
|
params[:direction] == "asc" ? "↑" : "↓"
|
141
141
|
end
|
142
142
|
|
143
|
-
def
|
144
|
-
@
|
143
|
+
def workset
|
144
|
+
@work ||= Sidekiq::WorkSet.new
|
145
145
|
end
|
146
146
|
|
147
147
|
def processes
|
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
|
+
|
151
164
|
def stats
|
152
165
|
@stats ||= Sidekiq::Stats.new
|
153
166
|
end
|
154
167
|
|
155
|
-
def
|
168
|
+
def redis_url
|
156
169
|
Sidekiq.redis do |conn|
|
157
|
-
conn.
|
170
|
+
conn._config.server_url
|
158
171
|
end
|
159
172
|
end
|
160
173
|
|
161
|
-
def namespace
|
162
|
-
@ns ||= Sidekiq.redis { |conn| conn.respond_to?(:namespace) ? conn.namespace : nil }
|
163
|
-
end
|
164
|
-
|
165
174
|
def redis_info
|
166
|
-
Sidekiq.redis_info
|
175
|
+
Sidekiq.default_configuration.redis_info
|
167
176
|
end
|
168
177
|
|
169
178
|
def root_path
|
@@ -175,7 +184,7 @@ module Sidekiq
|
|
175
184
|
end
|
176
185
|
|
177
186
|
def current_status
|
178
|
-
|
187
|
+
workset.size == 0 ? "idle" : "active"
|
179
188
|
end
|
180
189
|
|
181
190
|
def relative_time(time)
|
@@ -301,7 +310,7 @@ module Sidekiq
|
|
301
310
|
end
|
302
311
|
|
303
312
|
def environment_title_prefix
|
304
|
-
environment = Sidekiq.
|
313
|
+
environment = Sidekiq.default_configuration[:environment] || ENV["APP_ENV"] || ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "development"
|
305
314
|
|
306
315
|
"[#{environment.upcase}] " unless environment == "production"
|
307
316
|
end
|
@@ -314,13 +323,6 @@ module Sidekiq
|
|
314
323
|
Time.now.utc.strftime("%H:%M:%S UTC")
|
315
324
|
end
|
316
325
|
|
317
|
-
def redis_connection_and_namespace
|
318
|
-
@redis_connection_and_namespace ||= begin
|
319
|
-
namespace_suffix = namespace.nil? ? "" : "##{namespace}"
|
320
|
-
"#{redis_connection}#{namespace_suffix}"
|
321
|
-
end
|
322
|
-
end
|
323
|
-
|
324
326
|
def retry_or_delete_or_kill(job, params)
|
325
327
|
if params["retry"]
|
326
328
|
job.retry
|
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
|
@@ -75,14 +76,6 @@ module Sidekiq
|
|
75
76
|
send(:"#{attribute}=", value)
|
76
77
|
end
|
77
78
|
|
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
79
|
attr_accessor :app_url, :redis_pool
|
87
80
|
attr_writer :locales, :views
|
88
81
|
end
|
@@ -129,10 +122,6 @@ module Sidekiq
|
|
129
122
|
send(:"#{attribute}=", value)
|
130
123
|
end
|
131
124
|
|
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
125
|
def self.register(extension)
|
137
126
|
extension.registered(WebApplication)
|
138
127
|
end
|
@@ -144,7 +133,7 @@ module Sidekiq
|
|
144
133
|
m = middlewares
|
145
134
|
|
146
135
|
rules = []
|
147
|
-
rules = [[:all, {"
|
136
|
+
rules = [[:all, {"cache-control" => "public, max-age=86400"}]] unless ENV["SIDEKIQ_WEB_TESTING"]
|
148
137
|
|
149
138
|
::Rack::Builder.new do
|
150
139
|
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,14 +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
|
-
require "sidekiq/
|
33
|
+
require "sidekiq/transaction_aware_client"
|
9
34
|
require "sidekiq/job"
|
10
|
-
require "sidekiq/
|
11
|
-
require "sidekiq/
|
35
|
+
require "sidekiq/worker_compatibility_alias"
|
36
|
+
require "sidekiq/redis_client_adapter"
|
12
37
|
|
13
38
|
require "json"
|
14
39
|
|
@@ -16,254 +41,106 @@ module Sidekiq
|
|
16
41
|
NAME = "Sidekiq"
|
17
42
|
LICENSE = "See LICENSE and the LGPL-3.0 for licensing details."
|
18
43
|
|
19
|
-
DEFAULTS = {
|
20
|
-
queues: [],
|
21
|
-
labels: [],
|
22
|
-
concurrency: 10,
|
23
|
-
require: ".",
|
24
|
-
strict: true,
|
25
|
-
environment: nil,
|
26
|
-
timeout: 25,
|
27
|
-
poll_interval_average: nil,
|
28
|
-
average_scheduled_poll_interval: 5,
|
29
|
-
on_complex_arguments: :warn,
|
30
|
-
error_handlers: [],
|
31
|
-
death_handlers: [],
|
32
|
-
lifecycle_events: {
|
33
|
-
startup: [],
|
34
|
-
quiet: [],
|
35
|
-
shutdown: [],
|
36
|
-
heartbeat: []
|
37
|
-
},
|
38
|
-
dead_max_jobs: 10_000,
|
39
|
-
dead_timeout_in_seconds: 180 * 24 * 60 * 60, # 6 months
|
40
|
-
reloader: proc { |&block| block.call }
|
41
|
-
}
|
42
|
-
|
43
|
-
DEFAULT_WORKER_OPTIONS = {
|
44
|
-
"retry" => true,
|
45
|
-
"queue" => "default"
|
46
|
-
}
|
47
|
-
|
48
|
-
FAKE_INFO = {
|
49
|
-
"redis_version" => "9.9.9",
|
50
|
-
"uptime_in_days" => "9999",
|
51
|
-
"connected_clients" => "9999",
|
52
|
-
"used_memory_human" => "9P",
|
53
|
-
"used_memory_peak_human" => "9P"
|
54
|
-
}
|
55
|
-
|
56
44
|
def self.❨╯°□°❩╯︵┻━┻
|
57
|
-
puts "
|
58
|
-
end
|
59
|
-
|
60
|
-
def self.options
|
61
|
-
@options ||= DEFAULTS.dup
|
62
|
-
end
|
63
|
-
|
64
|
-
def self.options=(opts)
|
65
|
-
@options = opts
|
66
|
-
end
|
67
|
-
|
68
|
-
##
|
69
|
-
# Configuration for Sidekiq server, use like:
|
70
|
-
#
|
71
|
-
# Sidekiq.configure_server do |config|
|
72
|
-
# config.redis = { :namespace => 'myapp', :size => 25, :url => 'redis://myhost:8877/0' }
|
73
|
-
# config.server_middleware do |chain|
|
74
|
-
# chain.add MyServerHook
|
75
|
-
# end
|
76
|
-
# end
|
77
|
-
def self.configure_server
|
78
|
-
yield self if server?
|
79
|
-
end
|
80
|
-
|
81
|
-
##
|
82
|
-
# Configuration for Sidekiq client, use like:
|
83
|
-
#
|
84
|
-
# Sidekiq.configure_client do |config|
|
85
|
-
# config.redis = { :namespace => 'myapp', :size => 1, :url => 'redis://myhost:8877/0' }
|
86
|
-
# end
|
87
|
-
def self.configure_client
|
88
|
-
yield self unless server?
|
45
|
+
puts "Take a deep breath and count to ten..."
|
89
46
|
end
|
90
47
|
|
91
48
|
def self.server?
|
92
49
|
defined?(Sidekiq::CLI)
|
93
50
|
end
|
94
51
|
|
95
|
-
def self.
|
96
|
-
|
97
|
-
redis_pool.with do |conn|
|
98
|
-
retryable = true
|
99
|
-
begin
|
100
|
-
yield conn
|
101
|
-
rescue Redis::BaseError => ex
|
102
|
-
# 2550 Failover can cause the server to become a replica, need
|
103
|
-
# to disconnect and reopen the socket to get back to the primary.
|
104
|
-
# 4495 Use the same logic if we have a "Not enough replicas" error from the primary
|
105
|
-
# 4985 Use the same logic when a blocking command is force-unblocked
|
106
|
-
# The same retry logic is also used in client.rb
|
107
|
-
if retryable && ex.message =~ /READONLY|NOREPLICAS|UNBLOCKED/
|
108
|
-
conn.disconnect!
|
109
|
-
retryable = false
|
110
|
-
retry
|
111
|
-
end
|
112
|
-
raise
|
113
|
-
end
|
114
|
-
end
|
115
|
-
end
|
116
|
-
|
117
|
-
def self.redis_info
|
118
|
-
redis do |conn|
|
119
|
-
# admin commands can't go through redis-namespace starting
|
120
|
-
# in redis-namespace 2.0
|
121
|
-
if conn.respond_to?(:namespace)
|
122
|
-
conn.redis.info
|
123
|
-
else
|
124
|
-
conn.info
|
125
|
-
end
|
126
|
-
rescue Redis::CommandError => ex
|
127
|
-
# 2850 return fake version when INFO command has (probably) been renamed
|
128
|
-
raise unless /unknown command/.match?(ex.message)
|
129
|
-
FAKE_INFO
|
130
|
-
end
|
131
|
-
end
|
132
|
-
|
133
|
-
def self.redis_pool
|
134
|
-
@redis ||= Sidekiq::RedisConnection.create
|
135
|
-
end
|
136
|
-
|
137
|
-
def self.redis=(hash)
|
138
|
-
@redis = if hash.is_a?(ConnectionPool)
|
139
|
-
hash
|
140
|
-
else
|
141
|
-
Sidekiq::RedisConnection.create(hash)
|
142
|
-
end
|
143
|
-
end
|
144
|
-
|
145
|
-
def self.client_middleware
|
146
|
-
@client_chain ||= Middleware::Chain.new
|
147
|
-
yield @client_chain if block_given?
|
148
|
-
@client_chain
|
52
|
+
def self.load_json(string)
|
53
|
+
JSON.parse(string)
|
149
54
|
end
|
150
55
|
|
151
|
-
def self.
|
152
|
-
|
153
|
-
yield @server_chain if block_given?
|
154
|
-
@server_chain
|
56
|
+
def self.dump_json(object)
|
57
|
+
JSON.generate(object)
|
155
58
|
end
|
156
59
|
|
157
|
-
def self.
|
158
|
-
|
60
|
+
def self.pro?
|
61
|
+
defined?(Sidekiq::Pro)
|
159
62
|
end
|
160
63
|
|
161
|
-
def self.
|
162
|
-
|
163
|
-
@default_worker_options = default_worker_options.merge(hash.transform_keys(&:to_s))
|
64
|
+
def self.ent?
|
65
|
+
defined?(Sidekiq::Enterprise)
|
164
66
|
end
|
165
67
|
|
166
|
-
def self.
|
167
|
-
|
68
|
+
def self.redis_pool
|
69
|
+
(Thread.current[:sidekiq_capsule] || default_configuration).redis_pool
|
168
70
|
end
|
169
71
|
|
170
|
-
|
171
|
-
|
172
|
-
# the job dies. It's the notification to your application
|
173
|
-
# that this job will not succeed without manual intervention.
|
174
|
-
#
|
175
|
-
# Sidekiq.configure_server do |config|
|
176
|
-
# config.death_handlers << ->(job, ex) do
|
177
|
-
# end
|
178
|
-
# end
|
179
|
-
def self.death_handlers
|
180
|
-
options[:death_handlers]
|
72
|
+
def self.redis(&block)
|
73
|
+
(Thread.current[:sidekiq_capsule] || default_configuration).redis(&block)
|
181
74
|
end
|
182
75
|
|
183
|
-
def self.
|
184
|
-
|
76
|
+
def self.strict_args!(mode = :raise)
|
77
|
+
Sidekiq::Config::DEFAULTS[:on_complex_arguments] = mode
|
185
78
|
end
|
186
79
|
|
187
|
-
def self.
|
188
|
-
|
80
|
+
def self.default_job_options=(hash)
|
81
|
+
@default_job_options = default_job_options.merge(hash.transform_keys(&:to_s))
|
189
82
|
end
|
190
83
|
|
191
|
-
def self.
|
192
|
-
@
|
193
|
-
Sidekiq::Logger::Formatters::WithoutTimestamp.new
|
194
|
-
else
|
195
|
-
Sidekiq::Logger::Formatters::Pretty.new
|
196
|
-
end
|
84
|
+
def self.default_job_options
|
85
|
+
@default_job_options ||= {"retry" => true, "queue" => "default"}
|
197
86
|
end
|
198
87
|
|
199
|
-
def self.
|
200
|
-
@
|
201
|
-
logger.formatter = log_formatter
|
88
|
+
def self.default_configuration
|
89
|
+
@config ||= Sidekiq::Config.new
|
202
90
|
end
|
203
91
|
|
204
92
|
def self.logger
|
205
|
-
|
206
|
-
end
|
207
|
-
|
208
|
-
def self.logger=(logger)
|
209
|
-
if logger.nil?
|
210
|
-
self.logger.level = Logger::FATAL
|
211
|
-
return self.logger
|
212
|
-
end
|
213
|
-
|
214
|
-
logger.extend(Sidekiq::LoggingUtils)
|
215
|
-
|
216
|
-
@logger = logger
|
93
|
+
default_configuration.logger
|
217
94
|
end
|
218
95
|
|
219
|
-
def self.
|
220
|
-
|
96
|
+
def self.configure_server(&block)
|
97
|
+
(@config_blocks ||= []) << block
|
98
|
+
yield default_configuration if server?
|
221
99
|
end
|
222
100
|
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
#
|
227
|
-
# See sidekiq/scheduled.rb for an in-depth explanation of this value
|
228
|
-
def self.average_scheduled_poll_interval=(interval)
|
229
|
-
options[:average_scheduled_poll_interval] = interval
|
101
|
+
def self.freeze!
|
102
|
+
@frozen = true
|
103
|
+
@config_blocks = nil
|
230
104
|
end
|
231
105
|
|
232
|
-
#
|
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.
|
233
109
|
#
|
234
|
-
# Sidekiq.
|
235
|
-
# config.
|
110
|
+
# inst = Sidekiq.configure_embed do |config|
|
111
|
+
# config.queues = %w[critical default low]
|
236
112
|
# end
|
113
|
+
# inst.run
|
114
|
+
# sleep 10
|
115
|
+
# inst.terminate
|
237
116
|
#
|
238
|
-
#
|
239
|
-
|
240
|
-
options[:error_handlers]
|
241
|
-
end
|
242
|
-
|
243
|
-
# Register a block to run at a point in the Sidekiq lifecycle.
|
244
|
-
# :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.
|
245
119
|
#
|
246
|
-
#
|
247
|
-
#
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
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)
|
255
132
|
end
|
256
133
|
|
257
|
-
def self.
|
258
|
-
|
134
|
+
def self.configure_client
|
135
|
+
yield default_configuration unless server?
|
259
136
|
end
|
260
137
|
|
261
|
-
# We are shutting down Sidekiq but what about
|
138
|
+
# We are shutting down Sidekiq but what about threads that
|
262
139
|
# are working on some long job? This error is
|
263
|
-
# raised in
|
140
|
+
# raised in jobs that have not finished within the hard
|
264
141
|
# timeout limit. This is needed to rollback db transactions,
|
265
142
|
# otherwise Ruby's Thread#kill will commit. See #377.
|
266
|
-
# DO NOT RESCUE THIS ERROR IN YOUR
|
143
|
+
# DO NOT RESCUE THIS ERROR IN YOUR JOBS
|
267
144
|
class Shutdown < Interrupt; end
|
268
145
|
end
|
269
146
|
|
data/sidekiq.gemspec
CHANGED
@@ -9,10 +9,10 @@ Gem::Specification.new do |gem|
|
|
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",
|
@@ -22,7 +22,31 @@ Gem::Specification.new do |gem|
|
|
22
22
|
"source_code_uri" => "https://github.com/mperham/sidekiq"
|
23
23
|
}
|
24
24
|
|
25
|
-
gem.add_dependency "redis", ">=
|
26
|
-
gem.add_dependency "connection_pool", ">= 2.
|
27
|
-
gem.add_dependency "rack", "
|
25
|
+
gem.add_dependency "redis-client", ">= 0.9.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
|
+
####################################################
|
32
|
+
|
33
|
+
|
34
|
+
█████████ █████ ██████████ ██████████ █████ ████ █████ ██████ ██████████ █████
|
35
|
+
███░░░░░███░░███ ░░███░░░░███ ░░███░░░░░█░░███ ███░ ░░███ ███░░░░███ ░███░░░░███ ███░░░███
|
36
|
+
░███ ░░░ ░███ ░███ ░░███ ░███ █ ░ ░███ ███ ░███ ███ ░░███ ░░░ ███ ███ ░░███
|
37
|
+
░░█████████ ░███ ░███ ░███ ░██████ ░███████ ░███ ░███ ░███ ███ ░███ ░███
|
38
|
+
░░░░░░░░███ ░███ ░███ ░███ ░███░░█ ░███░░███ ░███ ░███ ██░███ ███ ░███ ░███
|
39
|
+
███ ░███ ░███ ░███ ███ ░███ ░ █ ░███ ░░███ ░███ ░░███ ░░████ ███ ░░███ ███
|
40
|
+
░░█████████ █████ ██████████ ██████████ █████ ░░████ █████ ░░░██████░██ ███ ██ ░░░█████░
|
41
|
+
░░░░░░░░░ ░░░░░ ░░░░░░░░░░ ░░░░░░░░░░ ░░░░░ ░░░░ ░░░░░ ░░░░░░ ░░ ░░░ ░░ ░░░░░░
|
42
|
+
|
43
|
+
|
44
|
+
WARNING: This is a beta release, expect breakage!
|
45
|
+
|
46
|
+
1. Use `gem 'sidekiq', '<7'` in your Gemfile if you don't want to be a beta tester.
|
47
|
+
2. Read the release notes at https://github.com/mperham/sidekiq/blob/main/docs/7.0-Upgrade.md
|
48
|
+
3. Search for open/closed issues at https://github.com/mperham/sidekiq/issues/
|
49
|
+
|
50
|
+
####################################################
|
51
|
+
EOM
|
28
52
|
end
|
@@ -9,7 +9,9 @@ var ready = (callback) => {
|
|
9
9
|
else document.addEventListener("DOMContentLoaded", callback);
|
10
10
|
}
|
11
11
|
|
12
|
-
ready(
|
12
|
+
ready(addListeners)
|
13
|
+
|
14
|
+
function addListeners() {
|
13
15
|
document.querySelectorAll(".check_all").forEach(node => {
|
14
16
|
node.addEventListener("click", event => {
|
15
17
|
node.closest('table').querySelectorAll('input[type=checkbox]').forEach(inp => { inp.checked = !!node.checked; });
|
@@ -26,42 +28,48 @@ ready(() => {
|
|
26
28
|
})
|
27
29
|
|
28
30
|
document.querySelectorAll("[data-toggle]").forEach(node => {
|
29
|
-
node.addEventListener("click",
|
30
|
-
var targName = node.getAttribute("data-toggle");
|
31
|
-
var full = document.getElementById(targName + "_full");
|
32
|
-
if (full.style.display == "block") {
|
33
|
-
full.style.display = 'none';
|
34
|
-
} else {
|
35
|
-
full.style.display = 'block';
|
36
|
-
}
|
37
|
-
})
|
31
|
+
node.addEventListener("click", addDataToggleListeners)
|
38
32
|
})
|
39
33
|
|
40
34
|
updateFuzzyTimes();
|
35
|
+
setLivePollFromUrl();
|
41
36
|
|
42
37
|
var buttons = document.querySelectorAll(".live-poll");
|
43
38
|
if (buttons.length > 0) {
|
44
39
|
buttons.forEach(node => {
|
45
|
-
node.addEventListener("click",
|
46
|
-
if (localStorage.sidekiqLivePoll == "enabled") {
|
47
|
-
localStorage.sidekiqLivePoll = "disabled";
|
48
|
-
clearTimeout(livePollTimer);
|
49
|
-
livePollTimer = null;
|
50
|
-
} else {
|
51
|
-
localStorage.sidekiqLivePoll = "enabled";
|
52
|
-
livePollCallback();
|
53
|
-
}
|
54
|
-
|
55
|
-
updateLivePollButton();
|
56
|
-
})
|
40
|
+
node.addEventListener("click", addPollingListeners)
|
57
41
|
});
|
58
42
|
|
59
43
|
updateLivePollButton();
|
60
|
-
if (localStorage.sidekiqLivePoll == "enabled") {
|
44
|
+
if (localStorage.sidekiqLivePoll == "enabled" && !livePollTimer) {
|
61
45
|
scheduleLivePoll();
|
62
46
|
}
|
63
47
|
}
|
64
|
-
}
|
48
|
+
}
|
49
|
+
|
50
|
+
function addPollingListeners(_event) {
|
51
|
+
if (localStorage.sidekiqLivePoll == "enabled") {
|
52
|
+
localStorage.sidekiqLivePoll = "disabled";
|
53
|
+
clearTimeout(livePollTimer);
|
54
|
+
livePollTimer = null;
|
55
|
+
} else {
|
56
|
+
localStorage.sidekiqLivePoll = "enabled";
|
57
|
+
livePollCallback();
|
58
|
+
}
|
59
|
+
|
60
|
+
updateLivePollButton();
|
61
|
+
}
|
62
|
+
|
63
|
+
function addDataToggleListeners(event) {
|
64
|
+
var source = event.target || event.srcElement;
|
65
|
+
var targName = source.getAttribute("data-toggle");
|
66
|
+
var full = document.getElementById(targName);
|
67
|
+
if (full.style.display == "block") {
|
68
|
+
full.style.display = 'none';
|
69
|
+
} else {
|
70
|
+
full.style.display = 'block';
|
71
|
+
}
|
72
|
+
}
|
65
73
|
|
66
74
|
function updateFuzzyTimes() {
|
67
75
|
var locale = document.body.getAttribute("data-locale");
|
@@ -76,6 +84,14 @@ function updateFuzzyTimes() {
|
|
76
84
|
t.cancel();
|
77
85
|
}
|
78
86
|
|
87
|
+
function setLivePollFromUrl() {
|
88
|
+
var url_params = new URL(window.location.href).searchParams
|
89
|
+
|
90
|
+
if (url_params.get("poll") == "true") {
|
91
|
+
localStorage.sidekiqLivePoll = "enabled";
|
92
|
+
}
|
93
|
+
}
|
94
|
+
|
79
95
|
function updateLivePollButton() {
|
80
96
|
if (localStorage.sidekiqLivePoll == "enabled") {
|
81
97
|
document.querySelectorAll('.live-poll-stop').forEach(box => { box.style.display = "inline-block" })
|
@@ -89,7 +105,19 @@ function updateLivePollButton() {
|
|
89
105
|
function livePollCallback() {
|
90
106
|
clearTimeout(livePollTimer);
|
91
107
|
|
92
|
-
fetch(window.location.href)
|
108
|
+
fetch(window.location.href)
|
109
|
+
.then(checkResponse)
|
110
|
+
.then(resp => resp.text())
|
111
|
+
.then(replacePage)
|
112
|
+
.catch(showError)
|
113
|
+
.finally(scheduleLivePoll)
|
114
|
+
}
|
115
|
+
|
116
|
+
function checkResponse(resp) {
|
117
|
+
if (!resp.ok) {
|
118
|
+
throw response.error();
|
119
|
+
}
|
120
|
+
return resp
|
93
121
|
}
|
94
122
|
|
95
123
|
function scheduleLivePoll() {
|
@@ -107,5 +135,9 @@ function replacePage(text) {
|
|
107
135
|
var header_status = doc.querySelector('.status')
|
108
136
|
document.querySelector('.status').replaceWith(header_status)
|
109
137
|
|
110
|
-
|
138
|
+
addListeners();
|
139
|
+
}
|
140
|
+
|
141
|
+
function showError(error) {
|
142
|
+
console.error(error)
|
111
143
|
}
|