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