sidekiq 5.2.7 → 8.0.5
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 +845 -8
- data/LICENSE.txt +9 -0
- data/README.md +54 -54
- data/bin/multi_queue_bench +271 -0
- data/bin/sidekiq +22 -3
- data/bin/sidekiqload +219 -112
- data/bin/sidekiqmon +11 -0
- data/bin/webload +69 -0
- data/lib/active_job/queue_adapters/sidekiq_adapter.rb +120 -0
- data/lib/generators/sidekiq/job_generator.rb +59 -0
- data/lib/generators/sidekiq/templates/{worker.rb.erb → job.rb.erb} +2 -2
- data/lib/generators/sidekiq/templates/{worker_spec.rb.erb → job_spec.rb.erb} +1 -1
- data/lib/generators/sidekiq/templates/{worker_test.rb.erb → job_test.rb.erb} +1 -1
- data/lib/sidekiq/api.rb +757 -373
- data/lib/sidekiq/capsule.rb +132 -0
- data/lib/sidekiq/cli.rb +210 -233
- data/lib/sidekiq/client.rb +145 -103
- data/lib/sidekiq/component.rb +128 -0
- data/lib/sidekiq/config.rb +315 -0
- data/lib/sidekiq/deploy.rb +64 -0
- data/lib/sidekiq/embedded.rb +64 -0
- data/lib/sidekiq/fetch.rb +49 -42
- data/lib/sidekiq/iterable_job.rb +56 -0
- data/lib/sidekiq/job/interrupt_handler.rb +24 -0
- data/lib/sidekiq/job/iterable/active_record_enumerator.rb +53 -0
- data/lib/sidekiq/job/iterable/csv_enumerator.rb +47 -0
- data/lib/sidekiq/job/iterable/enumerators.rb +135 -0
- data/lib/sidekiq/job/iterable.rb +306 -0
- data/lib/sidekiq/job.rb +385 -0
- data/lib/sidekiq/job_logger.rb +34 -7
- data/lib/sidekiq/job_retry.rb +164 -109
- data/lib/sidekiq/job_util.rb +113 -0
- data/lib/sidekiq/launcher.rb +208 -107
- data/lib/sidekiq/logger.rb +80 -0
- data/lib/sidekiq/manager.rb +42 -46
- data/lib/sidekiq/metrics/query.rb +184 -0
- data/lib/sidekiq/metrics/shared.rb +109 -0
- data/lib/sidekiq/metrics/tracking.rb +150 -0
- data/lib/sidekiq/middleware/chain.rb +113 -56
- data/lib/sidekiq/middleware/current_attributes.rb +119 -0
- data/lib/sidekiq/middleware/i18n.rb +7 -7
- data/lib/sidekiq/middleware/modules.rb +23 -0
- data/lib/sidekiq/monitor.rb +147 -0
- data/lib/sidekiq/paginator.rb +41 -16
- data/lib/sidekiq/processor.rb +146 -127
- data/lib/sidekiq/profiler.rb +72 -0
- data/lib/sidekiq/rails.rb +46 -43
- data/lib/sidekiq/redis_client_adapter.rb +113 -0
- data/lib/sidekiq/redis_connection.rb +79 -108
- data/lib/sidekiq/ring_buffer.rb +31 -0
- data/lib/sidekiq/scheduled.rb +112 -50
- data/lib/sidekiq/sd_notify.rb +149 -0
- data/lib/sidekiq/systemd.rb +26 -0
- data/lib/sidekiq/testing/inline.rb +6 -5
- data/lib/sidekiq/testing.rb +91 -90
- data/lib/sidekiq/transaction_aware_client.rb +51 -0
- data/lib/sidekiq/version.rb +7 -1
- data/lib/sidekiq/web/action.rb +125 -60
- data/lib/sidekiq/web/application.rb +363 -259
- data/lib/sidekiq/web/config.rb +120 -0
- data/lib/sidekiq/web/csrf_protection.rb +183 -0
- data/lib/sidekiq/web/helpers.rb +241 -120
- data/lib/sidekiq/web/router.rb +62 -71
- data/lib/sidekiq/web.rb +69 -161
- data/lib/sidekiq/worker_compatibility_alias.rb +13 -0
- data/lib/sidekiq.rb +94 -182
- data/sidekiq.gemspec +26 -16
- data/web/assets/images/apple-touch-icon.png +0 -0
- data/web/assets/javascripts/application.js +150 -61
- data/web/assets/javascripts/base-charts.js +120 -0
- data/web/assets/javascripts/chart.min.js +13 -0
- data/web/assets/javascripts/chartjs-adapter-date-fns.min.js +7 -0
- data/web/assets/javascripts/chartjs-plugin-annotation.min.js +7 -0
- data/web/assets/javascripts/dashboard-charts.js +194 -0
- data/web/assets/javascripts/dashboard.js +41 -293
- data/web/assets/javascripts/metrics.js +280 -0
- data/web/assets/stylesheets/style.css +766 -0
- data/web/locales/ar.yml +72 -65
- data/web/locales/cs.yml +63 -62
- data/web/locales/da.yml +61 -53
- data/web/locales/de.yml +66 -53
- data/web/locales/el.yml +44 -24
- data/web/locales/en.yml +94 -66
- data/web/locales/es.yml +92 -54
- data/web/locales/fa.yml +66 -65
- data/web/locales/fr.yml +83 -62
- data/web/locales/gd.yml +99 -0
- data/web/locales/he.yml +66 -64
- data/web/locales/hi.yml +60 -59
- data/web/locales/it.yml +93 -54
- data/web/locales/ja.yml +75 -64
- data/web/locales/ko.yml +53 -52
- data/web/locales/lt.yml +84 -0
- data/web/locales/nb.yml +62 -61
- data/web/locales/nl.yml +53 -52
- data/web/locales/pl.yml +46 -45
- data/web/locales/{pt-br.yml → pt-BR.yml} +84 -56
- data/web/locales/pt.yml +52 -51
- data/web/locales/ru.yml +69 -63
- data/web/locales/sv.yml +54 -53
- data/web/locales/ta.yml +61 -60
- data/web/locales/tr.yml +101 -0
- data/web/locales/uk.yml +86 -61
- data/web/locales/ur.yml +65 -64
- data/web/locales/vi.yml +84 -0
- data/web/locales/zh-CN.yml +106 -0
- data/web/locales/{zh-tw.yml → zh-TW.yml} +43 -9
- data/web/views/_footer.erb +31 -19
- data/web/views/_job_info.erb +94 -75
- data/web/views/_metrics_period_select.erb +15 -0
- data/web/views/_nav.erb +14 -21
- data/web/views/_paging.erb +23 -19
- data/web/views/_poll_link.erb +3 -6
- data/web/views/_summary.erb +23 -23
- data/web/views/busy.erb +139 -87
- data/web/views/dashboard.erb +82 -53
- data/web/views/dead.erb +31 -27
- data/web/views/filtering.erb +6 -0
- data/web/views/layout.erb +15 -29
- data/web/views/metrics.erb +84 -0
- data/web/views/metrics_for_job.erb +58 -0
- data/web/views/morgue.erb +60 -70
- data/web/views/profiles.erb +43 -0
- data/web/views/queue.erb +50 -39
- data/web/views/queues.erb +45 -29
- data/web/views/retries.erb +65 -75
- data/web/views/retry.erb +32 -27
- data/web/views/scheduled.erb +58 -52
- data/web/views/scheduled_job_info.erb +1 -1
- metadata +96 -76
- data/.circleci/config.yml +0 -61
- data/.github/contributing.md +0 -32
- data/.github/issue_template.md +0 -11
- data/.gitignore +0 -15
- data/.travis.yml +0 -11
- data/3.0-Upgrade.md +0 -70
- data/4.0-Upgrade.md +0 -53
- data/5.0-Upgrade.md +0 -56
- data/COMM-LICENSE +0 -97
- data/Ent-Changes.md +0 -238
- data/Gemfile +0 -23
- data/LICENSE +0 -9
- data/Pro-2.0-Upgrade.md +0 -138
- data/Pro-3.0-Upgrade.md +0 -44
- data/Pro-4.0-Upgrade.md +0 -35
- data/Pro-Changes.md +0 -759
- data/Rakefile +0 -9
- data/bin/sidekiqctl +0 -20
- data/code_of_conduct.md +0 -50
- data/lib/generators/sidekiq/worker_generator.rb +0 -49
- data/lib/sidekiq/core_ext.rb +0 -1
- data/lib/sidekiq/ctl.rb +0 -221
- data/lib/sidekiq/delay.rb +0 -42
- data/lib/sidekiq/exception_handler.rb +0 -29
- data/lib/sidekiq/extensions/action_mailer.rb +0 -57
- data/lib/sidekiq/extensions/active_record.rb +0 -40
- data/lib/sidekiq/extensions/class_methods.rb +0 -40
- data/lib/sidekiq/extensions/generic_proxy.rb +0 -31
- data/lib/sidekiq/logging.rb +0 -122
- data/lib/sidekiq/middleware/server/active_record.rb +0 -23
- data/lib/sidekiq/util.rb +0 -66
- data/lib/sidekiq/worker.rb +0 -220
- data/web/assets/stylesheets/application-rtl.css +0 -246
- data/web/assets/stylesheets/application.css +0 -1144
- data/web/assets/stylesheets/bootstrap-rtl.min.css +0 -9
- data/web/assets/stylesheets/bootstrap.css +0 -5
- data/web/locales/zh-cn.yml +0 -68
- data/web/views/_status.erb +0 -4
data/lib/sidekiq/cli.rb
CHANGED
@@ -1,38 +1,38 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
$stdout.sync = true
|
3
4
|
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
7
|
-
require
|
8
|
-
require 'fileutils'
|
5
|
+
require "yaml"
|
6
|
+
require "optparse"
|
7
|
+
require "erb"
|
8
|
+
require "fileutils"
|
9
9
|
|
10
|
-
require
|
11
|
-
require
|
12
|
-
require
|
10
|
+
require "sidekiq"
|
11
|
+
require "sidekiq/config"
|
12
|
+
require "sidekiq/component"
|
13
|
+
require "sidekiq/capsule"
|
14
|
+
require "sidekiq/launcher"
|
13
15
|
|
14
|
-
module Sidekiq
|
16
|
+
module Sidekiq # :nodoc:
|
15
17
|
class CLI
|
16
|
-
include
|
17
|
-
include Singleton unless $TESTING
|
18
|
-
|
19
|
-
PROCTITLES = [
|
20
|
-
proc { 'sidekiq' },
|
21
|
-
proc { Sidekiq::VERSION },
|
22
|
-
proc { |me, data| data['tag'] },
|
23
|
-
proc { |me, data| "[#{Processor::WORKER_STATE.size} of #{data['concurrency']} busy]" },
|
24
|
-
proc { |me, data| "stopping" if me.stopping? },
|
25
|
-
]
|
18
|
+
include Sidekiq::Component
|
26
19
|
|
27
20
|
attr_accessor :launcher
|
28
21
|
attr_accessor :environment
|
22
|
+
attr_accessor :config
|
23
|
+
|
24
|
+
def parse(args = ARGV.dup)
|
25
|
+
@config ||= Sidekiq.default_configuration
|
29
26
|
|
30
|
-
def parse(args = ARGV)
|
31
27
|
setup_options(args)
|
32
28
|
initialize_logger
|
33
29
|
validate!
|
34
30
|
end
|
35
31
|
|
32
|
+
def self.instance
|
33
|
+
@instance ||= new
|
34
|
+
end
|
35
|
+
|
36
36
|
def jruby?
|
37
37
|
defined?(::JRUBY_VERSION)
|
38
38
|
end
|
@@ -40,187 +40,208 @@ module Sidekiq
|
|
40
40
|
# Code within this method is not tested because it alters
|
41
41
|
# global process state irreversibly. PRs which improve the
|
42
42
|
# test coverage of Sidekiq::CLI are welcomed.
|
43
|
-
def run
|
44
|
-
|
45
|
-
write_pid
|
46
|
-
boot_system
|
47
|
-
print_banner if environment == 'development' && $stdout.tty?
|
43
|
+
def run(boot_app: true, warmup: true)
|
44
|
+
boot_application if boot_app
|
48
45
|
|
49
|
-
|
50
|
-
|
51
|
-
# USR1 and USR2 don't work on the JVM
|
52
|
-
if !jruby?
|
53
|
-
sigs << 'USR1'
|
54
|
-
sigs << 'USR2'
|
46
|
+
if environment == "development" && $stdout.tty? && @config.logger.formatter.is_a?(Sidekiq::Logger::Formatters::Pretty)
|
47
|
+
print_banner
|
55
48
|
end
|
49
|
+
logger.info "Booted Rails #{::Rails.version} application in #{environment} environment" if rails_app?
|
56
50
|
|
51
|
+
self_read, self_write = IO.pipe
|
52
|
+
sigs = %w[INT TERM TTIN TSTP]
|
53
|
+
# USR1 and USR2 don't work on the JVM
|
54
|
+
sigs << "USR2" if Sidekiq.pro? && !jruby?
|
57
55
|
sigs.each do |sig|
|
58
|
-
|
59
|
-
|
60
|
-
|
56
|
+
old_handler = Signal.trap(sig) do
|
57
|
+
if old_handler.respond_to?(:call)
|
58
|
+
begin
|
59
|
+
old_handler.call
|
60
|
+
rescue Exception => exc
|
61
|
+
# signal handlers can't use Logger so puts only
|
62
|
+
puts ["Error in #{sig} handler", exc].inspect
|
63
|
+
end
|
61
64
|
end
|
62
|
-
|
63
|
-
puts "Signal #{sig} not supported"
|
65
|
+
self_write.puts(sig)
|
64
66
|
end
|
67
|
+
rescue ArgumentError
|
68
|
+
puts "Signal #{sig} not supported"
|
65
69
|
end
|
66
70
|
|
67
71
|
logger.info "Running in #{RUBY_DESCRIPTION}"
|
68
72
|
logger.info Sidekiq::LICENSE
|
69
|
-
logger.info "Upgrade to Sidekiq Pro for more features and support:
|
73
|
+
logger.info "Upgrade to Sidekiq Pro for more features and support: https://sidekiq.org" unless defined?(::Sidekiq::Pro)
|
70
74
|
|
71
75
|
# touch the connection pool so it is created before we
|
72
76
|
# fire startup and start multithreading.
|
73
|
-
|
74
|
-
|
75
|
-
|
77
|
+
info = @config.redis_info
|
78
|
+
ver = Gem::Version.new(info["redis_version"])
|
79
|
+
raise "You are connected to Redis #{ver}, Sidekiq requires Redis 7.0.0 or greater" if ver < Gem::Version.new("7.0.0")
|
80
|
+
|
81
|
+
maxmemory_policy = info["maxmemory_policy"]
|
82
|
+
if maxmemory_policy != "noeviction" && maxmemory_policy != ""
|
83
|
+
# Redis Enterprise Cloud returns "" for their policy 😳
|
84
|
+
logger.warn <<~EOM
|
85
|
+
|
86
|
+
|
87
|
+
WARNING: Your Redis instance will evict Sidekiq data under heavy load.
|
88
|
+
The 'noeviction' maxmemory policy is recommended (current policy: '#{maxmemory_policy}').
|
89
|
+
See: https://github.com/sidekiq/sidekiq/wiki/Using-Redis#memory
|
90
|
+
|
91
|
+
EOM
|
92
|
+
end
|
76
93
|
|
77
94
|
# Since the user can pass us a connection pool explicitly in the initializer, we
|
78
95
|
# need to verify the size is large enough or else Sidekiq's performance is dramatically slowed.
|
79
|
-
|
80
|
-
|
81
|
-
|
96
|
+
@config.capsules.each_pair do |name, cap|
|
97
|
+
raise ArgumentError, "Pool size too small for #{name}" if cap.redis_pool.size < cap.concurrency
|
98
|
+
end
|
82
99
|
|
83
100
|
# cache process identity
|
84
|
-
|
101
|
+
@config[:identity] = identity
|
85
102
|
|
86
103
|
# Touch middleware so it isn't lazy loaded by multiple threads, #3043
|
87
|
-
|
104
|
+
@config.server_middleware
|
105
|
+
|
106
|
+
::Process.warmup if warmup && ::Process.respond_to?(:warmup) && ENV["RUBY_DISABLE_WARMUP"] != "1"
|
88
107
|
|
89
108
|
# Before this point, the process is initializing with just the main thread.
|
90
109
|
# Starting here the process will now have multiple threads running.
|
91
110
|
fire_event(:startup, reverse: false, reraise: true)
|
92
111
|
|
93
|
-
logger.debug { "Client Middleware: #{
|
94
|
-
logger.debug { "Server Middleware: #{
|
112
|
+
logger.debug { "Client Middleware: #{@config.default_capsule.client_middleware.map(&:klass).join(", ")}" }
|
113
|
+
logger.debug { "Server Middleware: #{@config.default_capsule.server_middleware.map(&:klass).join(", ")}" }
|
95
114
|
|
96
115
|
launch(self_read)
|
97
116
|
end
|
98
117
|
|
99
118
|
def launch(self_read)
|
100
|
-
if
|
101
|
-
logger.info
|
119
|
+
if environment == "development" && $stdout.tty?
|
120
|
+
logger.info "Starting processing, hit Ctrl-C to stop"
|
102
121
|
end
|
103
122
|
|
104
|
-
@launcher = Sidekiq::Launcher.new(
|
123
|
+
@launcher = Sidekiq::Launcher.new(@config)
|
105
124
|
|
106
125
|
begin
|
107
126
|
launcher.run
|
108
127
|
|
109
|
-
while
|
110
|
-
signal =
|
128
|
+
while self_read.wait_readable
|
129
|
+
signal = self_read.gets.strip
|
111
130
|
handle_signal(signal)
|
112
131
|
end
|
113
132
|
rescue Interrupt
|
114
|
-
logger.info
|
133
|
+
logger.info "Shutting down"
|
115
134
|
launcher.stop
|
116
|
-
# Explicitly exit so busy Processor threads can't block
|
117
|
-
# process shutdown.
|
118
135
|
logger.info "Bye!"
|
136
|
+
|
137
|
+
# Explicitly exit so busy Processor threads won't block process shutdown.
|
138
|
+
#
|
139
|
+
# NB: slow at_exit handlers will prevent a timely exit if they take
|
140
|
+
# a while to run. If Sidekiq is getting here but the process isn't exiting,
|
141
|
+
# use the TTIN signal to determine where things are stuck.
|
119
142
|
exit(0)
|
120
143
|
end
|
121
144
|
end
|
122
145
|
|
146
|
+
HOLIDAY_COLORS = {
|
147
|
+
# got other color-specific holidays from around the world?
|
148
|
+
# https://developer-book.com/post/definitive-guide-for-colored-text-in-terminal/#256-color-escape-codes
|
149
|
+
"3-17" => "\e[1;32m", # St. Patrick's Day green
|
150
|
+
"10-31" => "\e[38;5;208m" # Halloween orange
|
151
|
+
}
|
152
|
+
|
153
|
+
def self.day
|
154
|
+
@@day ||= begin
|
155
|
+
t = Date.today
|
156
|
+
"#{t.month}-#{t.day}"
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
def self.r
|
161
|
+
@@r ||= HOLIDAY_COLORS[day] || "\e[1;31m"
|
162
|
+
end
|
163
|
+
|
164
|
+
def self.b
|
165
|
+
@@b ||= HOLIDAY_COLORS[day] || "\e[30m"
|
166
|
+
end
|
167
|
+
|
168
|
+
def self.w
|
169
|
+
"\e[1;37m"
|
170
|
+
end
|
171
|
+
|
172
|
+
def self.reset
|
173
|
+
@@b = @@r = @@day = nil
|
174
|
+
"\e[0m"
|
175
|
+
end
|
176
|
+
|
123
177
|
def self.banner
|
124
|
-
%
|
125
|
-
m,
|
126
|
-
`$b
|
127
|
-
.ss, $$: .,d$
|
128
|
-
`$$P,d$P' .,md$P"'
|
129
|
-
,$$$$$
|
130
|
-
.d
|
131
|
-
$$^' `"
|
132
|
-
$:
|
133
|
-
`b :$$
|
134
|
-
$$:
|
135
|
-
$$ |____/|_
|
136
|
-
.d$$
|
137
|
-
}
|
178
|
+
%{
|
179
|
+
#{w} m,
|
180
|
+
#{w} `$b
|
181
|
+
#{w} .ss, $$: .,d$
|
182
|
+
#{w} `$$P,d$P' .,md$P"'
|
183
|
+
#{w} ,$$$$$b#{b}/#{w}md$$$P^'
|
184
|
+
#{w} .d$$$$$$#{b}/#{w}$$$P'
|
185
|
+
#{w} $$^' `"#{b}/#{w}$$$' #{r}____ _ _ _ _
|
186
|
+
#{w} $: #{b}'#{w},$$: #{r} / ___|(_) __| | ___| | _(_) __ _
|
187
|
+
#{w} `b :$$ #{r} \\___ \\| |/ _` |/ _ \\ |/ / |/ _` |
|
188
|
+
#{w} $$: #{r} ___) | | (_| | __/ <| | (_| |
|
189
|
+
#{w} $$ #{r}|____/|_|\\__,_|\\___|_|\\_\\_|\\__, |
|
190
|
+
#{w} .d$$ #{r} |_|
|
191
|
+
#{reset}}
|
138
192
|
end
|
139
193
|
|
140
194
|
SIGNAL_HANDLERS = {
|
141
195
|
# Ctrl-C in terminal
|
142
|
-
|
196
|
+
"INT" => ->(cli) { raise Interrupt },
|
143
197
|
# TERM is the signal that Sidekiq must exit.
|
144
198
|
# Heroku sends TERM and then waits 30 seconds for process to exit.
|
145
|
-
|
146
|
-
|
147
|
-
|
199
|
+
"TERM" => ->(cli) { raise Interrupt },
|
200
|
+
"TSTP" => ->(cli) {
|
201
|
+
cli.logger.info "Received TSTP, no longer accepting new work"
|
148
202
|
cli.launcher.quiet
|
149
203
|
},
|
150
|
-
|
151
|
-
Sidekiq.logger.info "Received TSTP, no longer accepting new work"
|
152
|
-
cli.launcher.quiet
|
153
|
-
},
|
154
|
-
'USR2' => ->(cli) {
|
155
|
-
if Sidekiq.options[:logfile]
|
156
|
-
Sidekiq.logger.info "Received USR2, reopening log file"
|
157
|
-
Sidekiq::Logging.reopen_logs
|
158
|
-
end
|
159
|
-
},
|
160
|
-
'TTIN' => ->(cli) {
|
204
|
+
"TTIN" => ->(cli) {
|
161
205
|
Thread.list.each do |thread|
|
162
|
-
|
206
|
+
cli.logger.warn "Thread TID-#{(thread.object_id ^ ::Process.pid).to_s(36)} #{thread.name}"
|
163
207
|
if thread.backtrace
|
164
|
-
|
208
|
+
cli.logger.warn thread.backtrace.join("\n")
|
165
209
|
else
|
166
|
-
|
210
|
+
cli.logger.warn "<no backtrace available>"
|
167
211
|
end
|
168
212
|
end
|
169
|
-
}
|
213
|
+
}
|
170
214
|
}
|
215
|
+
UNHANDLED_SIGNAL_HANDLER = ->(cli) { cli.logger.info "No signal handler registered, ignoring" }
|
216
|
+
SIGNAL_HANDLERS.default = UNHANDLED_SIGNAL_HANDLER
|
171
217
|
|
172
218
|
def handle_signal(sig)
|
173
|
-
|
174
|
-
|
175
|
-
if handy
|
176
|
-
handy.call(self)
|
177
|
-
else
|
178
|
-
Sidekiq.logger.info { "No signal handler for #{sig}" }
|
179
|
-
end
|
219
|
+
logger.debug "Got #{sig} signal"
|
220
|
+
SIGNAL_HANDLERS[sig].call(self)
|
180
221
|
end
|
181
222
|
|
182
223
|
private
|
183
224
|
|
184
225
|
def print_banner
|
185
|
-
puts "\e[
|
226
|
+
puts "\e[31m"
|
186
227
|
puts Sidekiq::CLI.banner
|
187
228
|
puts "\e[0m"
|
188
229
|
end
|
189
230
|
|
190
|
-
def daemonize
|
191
|
-
raise ArgumentError, "You really should set a logfile if you're going to daemonize" unless options[:logfile]
|
192
|
-
|
193
|
-
files_to_reopen = ObjectSpace.each_object(File).reject { |f| f.closed? }
|
194
|
-
::Process.daemon(true, true)
|
195
|
-
|
196
|
-
files_to_reopen.each do |file|
|
197
|
-
begin
|
198
|
-
file.reopen file.path, "a+"
|
199
|
-
file.sync = true
|
200
|
-
rescue ::Exception
|
201
|
-
end
|
202
|
-
end
|
203
|
-
|
204
|
-
[$stdout, $stderr].each do |io|
|
205
|
-
File.open(options[:logfile], 'ab') do |f|
|
206
|
-
io.reopen(f)
|
207
|
-
end
|
208
|
-
io.sync = true
|
209
|
-
end
|
210
|
-
$stdin.reopen('/dev/null')
|
211
|
-
|
212
|
-
initialize_logger
|
213
|
-
end
|
214
|
-
|
215
231
|
def set_environment(cli_env)
|
216
|
-
|
232
|
+
# See #984 for discussion.
|
233
|
+
# APP_ENV is now the preferred ENV term since it is not tech-specific.
|
234
|
+
# Both Sinatra 2.0+ and Sidekiq support this term.
|
235
|
+
# RAILS_ENV and RACK_ENV are there for legacy support.
|
236
|
+
@environment = cli_env || ENV["APP_ENV"] || ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "development"
|
237
|
+
config[:environment] = @environment
|
217
238
|
end
|
218
239
|
|
219
240
|
def symbolize_keys_deep!(hash)
|
220
241
|
hash.keys.each do |k|
|
221
242
|
symkey = k.respond_to?(:to_sym) ? k.to_sym : k
|
222
243
|
hash[symkey] = hash.delete k
|
223
|
-
symbolize_keys_deep! hash[symkey] if hash[symkey].
|
244
|
+
symbolize_keys_deep! hash[symkey] if hash[symkey].is_a? Hash
|
224
245
|
end
|
225
246
|
end
|
226
247
|
|
@@ -235,14 +256,14 @@ module Sidekiq
|
|
235
256
|
|
236
257
|
# check config file presence
|
237
258
|
if opts[:config_file]
|
238
|
-
|
259
|
+
unless File.exist?(opts[:config_file])
|
239
260
|
raise ArgumentError, "No such file #{opts[:config_file]}"
|
240
261
|
end
|
241
262
|
else
|
242
263
|
config_dir = if File.directory?(opts[:require].to_s)
|
243
|
-
File.join(opts[:require],
|
264
|
+
File.join(opts[:require], "config")
|
244
265
|
else
|
245
|
-
File.join(
|
266
|
+
File.join(@config[:require], "config")
|
246
267
|
end
|
247
268
|
|
248
269
|
%w[sidekiq.yml sidekiq.yml.erb].each do |config_file|
|
@@ -255,108 +276,89 @@ module Sidekiq
|
|
255
276
|
opts = parse_config(opts[:config_file]).merge(opts) if opts[:config_file]
|
256
277
|
|
257
278
|
# set defaults
|
258
|
-
opts[:queues] =
|
259
|
-
opts[:strict] = true if opts[:strict].nil?
|
279
|
+
opts[:queues] = ["default"] if opts[:queues].nil?
|
260
280
|
opts[:concurrency] = Integer(ENV["RAILS_MAX_THREADS"]) if opts[:concurrency].nil? && ENV["RAILS_MAX_THREADS"]
|
261
281
|
|
262
282
|
# merge with defaults
|
263
|
-
|
264
|
-
end
|
283
|
+
@config.merge!(opts)
|
265
284
|
|
266
|
-
|
267
|
-
|
268
|
-
|
285
|
+
@config.default_capsule.tap do |cap|
|
286
|
+
cap.queues = opts[:queues]
|
287
|
+
cap.concurrency = opts[:concurrency] || @config[:concurrency]
|
288
|
+
end
|
269
289
|
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
require 'rails'
|
275
|
-
if ::Rails::VERSION::MAJOR < 4
|
276
|
-
raise "Sidekiq no longer supports this version of Rails"
|
277
|
-
elsif ::Rails::VERSION::MAJOR == 4
|
278
|
-
# Painful contortions, see 1791 for discussion
|
279
|
-
# No autoloading, we want to force eager load for everything.
|
280
|
-
require File.expand_path("#{options[:require]}/config/application.rb")
|
281
|
-
::Rails::Application.initializer "sidekiq.eager_load" do
|
282
|
-
::Rails.application.config.eager_load = true
|
283
|
-
end
|
284
|
-
require 'sidekiq/rails'
|
285
|
-
require File.expand_path("#{options[:require]}/config/environment.rb")
|
286
|
-
else
|
287
|
-
require 'sidekiq/rails'
|
288
|
-
require File.expand_path("#{options[:require]}/config/environment.rb")
|
290
|
+
opts[:capsules]&.each do |name, cap_config|
|
291
|
+
@config.capsule(name.to_s) do |cap|
|
292
|
+
cap.queues = cap_config[:queues]
|
293
|
+
cap.concurrency = cap_config[:concurrency]
|
289
294
|
end
|
290
|
-
options[:tag] ||= default_tag
|
291
|
-
else
|
292
|
-
require options[:require]
|
293
295
|
end
|
294
296
|
end
|
295
297
|
|
296
|
-
def
|
297
|
-
|
298
|
-
|
299
|
-
if
|
300
|
-
|
301
|
-
|
298
|
+
def boot_application
|
299
|
+
ENV["RACK_ENV"] = ENV["RAILS_ENV"] = environment
|
300
|
+
|
301
|
+
if File.directory?(@config[:require])
|
302
|
+
require "rails"
|
303
|
+
if ::Rails::VERSION::MAJOR < 7
|
304
|
+
warn "Sidekiq #{Sidekiq::VERSION} only supports Rails 7+"
|
302
305
|
end
|
306
|
+
require "sidekiq/rails"
|
307
|
+
require File.expand_path("#{@config[:require]}/config/environment.rb")
|
308
|
+
@config[:tag] ||= default_tag(::Rails.root)
|
309
|
+
else
|
310
|
+
require @config[:require]
|
311
|
+
@config[:tag] ||= default_tag
|
303
312
|
end
|
304
|
-
name
|
305
313
|
end
|
306
314
|
|
307
315
|
def validate!
|
308
|
-
if !File.exist?(
|
309
|
-
|
316
|
+
if !File.exist?(@config[:require]) ||
|
317
|
+
(File.directory?(@config[:require]) && !File.exist?("#{@config[:require]}/config/application.rb"))
|
310
318
|
logger.info "=================================================================="
|
311
|
-
logger.info " Please point
|
312
|
-
logger.info " to load your
|
319
|
+
logger.info " Please point Sidekiq to a Rails application or a Ruby file "
|
320
|
+
logger.info " to load your job classes with -r [DIR|FILE]."
|
313
321
|
logger.info "=================================================================="
|
314
322
|
logger.info @parser
|
315
323
|
die(1)
|
316
324
|
end
|
317
325
|
|
318
326
|
[:concurrency, :timeout].each do |opt|
|
319
|
-
raise ArgumentError, "#{opt}: #{
|
327
|
+
raise ArgumentError, "#{opt}: #{@config[opt]} is not a valid value" if @config[opt].to_i <= 0
|
320
328
|
end
|
321
329
|
end
|
322
330
|
|
323
331
|
def parse_options(argv)
|
324
332
|
opts = {}
|
333
|
+
@parser = option_parser(opts)
|
334
|
+
@parser.parse!(argv)
|
335
|
+
opts
|
336
|
+
end
|
325
337
|
|
326
|
-
|
327
|
-
|
338
|
+
def option_parser(opts)
|
339
|
+
parser = OptionParser.new { |o|
|
340
|
+
o.on "-c", "--concurrency INT", "processor threads to use" do |arg|
|
328
341
|
opts[:concurrency] = Integer(arg)
|
329
342
|
end
|
330
343
|
|
331
|
-
o.on
|
332
|
-
opts[:daemon] = arg
|
333
|
-
puts "WARNING: Daemonization mode will be removed in Sidekiq 6.0, see #4045. Please use a proper process supervisor to start and manage your services"
|
334
|
-
end
|
335
|
-
|
336
|
-
o.on '-e', '--environment ENV', "Application environment" do |arg|
|
344
|
+
o.on "-e", "--environment ENV", "Application environment" do |arg|
|
337
345
|
opts[:environment] = arg
|
338
346
|
end
|
339
347
|
|
340
|
-
o.on
|
348
|
+
o.on "-g", "--tag TAG", "Process tag for procline" do |arg|
|
341
349
|
opts[:tag] = arg
|
342
350
|
end
|
343
351
|
|
344
|
-
# this index remains here for backwards compatibility but none of the Sidekiq
|
345
|
-
# family use this value anymore. it was used by Pro's original reliable_fetch.
|
346
|
-
o.on '-i', '--index INT', "unique process index on this machine" do |arg|
|
347
|
-
opts[:index] = Integer(arg.match(/\d+/)[0])
|
348
|
-
end
|
349
|
-
|
350
352
|
o.on "-q", "--queue QUEUE[,WEIGHT]", "Queues to process with optional weights" do |arg|
|
351
|
-
|
352
|
-
|
353
|
+
opts[:queues] ||= []
|
354
|
+
opts[:queues] << arg
|
353
355
|
end
|
354
356
|
|
355
|
-
o.on
|
357
|
+
o.on "-r", "--require [PATH|DIR]", "Location of Rails application with jobs or file to require" do |arg|
|
356
358
|
opts[:require] = arg
|
357
359
|
end
|
358
360
|
|
359
|
-
o.on
|
361
|
+
o.on "-t", "--timeout NUM", "Shutdown timeout" do |arg|
|
360
362
|
opts[:timeout] = Integer(arg)
|
361
363
|
end
|
362
364
|
|
@@ -364,54 +366,38 @@ module Sidekiq
|
|
364
366
|
opts[:verbose] = arg
|
365
367
|
end
|
366
368
|
|
367
|
-
o.on
|
369
|
+
o.on "-C", "--config PATH", "path to YAML config file" do |arg|
|
368
370
|
opts[:config_file] = arg
|
369
371
|
end
|
370
372
|
|
371
|
-
o.on
|
372
|
-
opts[:logfile] = arg
|
373
|
-
puts "WARNING: Logfile redirection will be removed in Sidekiq 6.0, see #4045. Sidekiq will only log to STDOUT"
|
374
|
-
end
|
375
|
-
|
376
|
-
o.on '-P', '--pidfile PATH', "path to pidfile" do |arg|
|
377
|
-
opts[:pidfile] = arg
|
378
|
-
puts "WARNING: PID file creation will be removed in Sidekiq 6.0, see #4045. Please use a proper process supervisor to start and manage your services"
|
379
|
-
end
|
380
|
-
|
381
|
-
o.on '-V', '--version', "Print version and exit" do |arg|
|
373
|
+
o.on "-V", "--version", "Print version and exit" do
|
382
374
|
puts "Sidekiq #{Sidekiq::VERSION}"
|
383
375
|
die(0)
|
384
376
|
end
|
385
|
-
|
377
|
+
}
|
386
378
|
|
387
|
-
|
388
|
-
|
389
|
-
logger.info
|
379
|
+
parser.banner = "sidekiq [options]"
|
380
|
+
parser.on_tail "-h", "--help", "Show help" do
|
381
|
+
logger.info parser
|
390
382
|
die 1
|
391
383
|
end
|
392
384
|
|
393
|
-
|
394
|
-
|
395
|
-
opts
|
385
|
+
parser
|
396
386
|
end
|
397
387
|
|
398
388
|
def initialize_logger
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
def write_pid
|
405
|
-
if path = options[:pidfile]
|
406
|
-
pidfile = File.expand_path(path)
|
407
|
-
File.open(pidfile, 'w') do |f|
|
408
|
-
f.puts ::Process.pid
|
409
|
-
end
|
389
|
+
if @config[:verbose] || ENV["DEBUG_INVOCATION"] == "1"
|
390
|
+
# DEBUG_INVOCATION is a systemd-ism triggered by
|
391
|
+
# RestartMode=debug. We turn on debugging when the
|
392
|
+
# sidekiq process crashes and is restarted with this flag.
|
393
|
+
@config.logger.level = ::Logger::DEBUG
|
410
394
|
end
|
411
395
|
end
|
412
396
|
|
413
397
|
def parse_config(path)
|
414
|
-
|
398
|
+
erb = ERB.new(File.read(path), trim_mode: "-")
|
399
|
+
erb.filename = File.expand_path(path)
|
400
|
+
opts = YAML.safe_load(erb.result, permitted_classes: [Symbol], aliases: true) || {}
|
415
401
|
|
416
402
|
if opts.respond_to? :deep_symbolize_keys!
|
417
403
|
opts.deep_symbolize_keys!
|
@@ -420,26 +406,17 @@ module Sidekiq
|
|
420
406
|
end
|
421
407
|
|
422
408
|
opts = opts.merge(opts.delete(environment.to_sym) || {})
|
423
|
-
|
409
|
+
opts.delete(:strict)
|
424
410
|
|
425
|
-
ns = opts.delete(:namespace)
|
426
|
-
if ns
|
427
|
-
# logger hasn't been initialized yet, puts is all we have.
|
428
|
-
puts("namespace should be set in your ruby initializer, is ignored in config file")
|
429
|
-
puts("config.redis = { :url => ..., :namespace => '#{ns}' }")
|
430
|
-
end
|
431
411
|
opts
|
432
412
|
end
|
433
413
|
|
434
|
-
def
|
435
|
-
|
436
|
-
end
|
437
|
-
|
438
|
-
def parse_queue(opts, queue, weight = nil)
|
439
|
-
opts[:queues] ||= []
|
440
|
-
raise ArgumentError, "queues: #{queue} cannot be defined twice" if opts[:queues].include?(queue)
|
441
|
-
[weight.to_i, 1].max.times { opts[:queues] << queue }
|
442
|
-
opts[:strict] = false if weight.to_i > 0
|
414
|
+
def rails_app?
|
415
|
+
defined?(::Rails) && ::Rails.respond_to?(:application)
|
443
416
|
end
|
444
417
|
end
|
445
418
|
end
|
419
|
+
|
420
|
+
require "sidekiq/systemd"
|
421
|
+
require "sidekiq/metrics/tracking"
|
422
|
+
require "sidekiq/job/interrupt_handler"
|