sidekiq 5.1.3 → 6.4.1
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 +391 -1
- data/LICENSE +3 -3
- data/README.md +23 -34
- data/bin/sidekiq +27 -3
- data/bin/sidekiqload +68 -62
- 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 +344 -243
- data/lib/sidekiq/cli.rb +209 -221
- data/lib/sidekiq/client.rb +62 -64
- data/lib/sidekiq/delay.rb +7 -6
- data/lib/sidekiq/exception_handler.rb +10 -12
- data/lib/sidekiq/extensions/action_mailer.rb +13 -22
- data/lib/sidekiq/extensions/active_record.rb +13 -10
- data/lib/sidekiq/extensions/class_methods.rb +14 -11
- data/lib/sidekiq/extensions/generic_proxy.rb +6 -4
- data/lib/sidekiq/fetch.rb +40 -32
- data/lib/sidekiq/job.rb +13 -0
- data/lib/sidekiq/job_logger.rb +35 -9
- data/lib/sidekiq/job_retry.rb +88 -68
- data/lib/sidekiq/job_util.rb +65 -0
- data/lib/sidekiq/launcher.rb +170 -73
- data/lib/sidekiq/logger.rb +170 -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 +20 -16
- data/lib/sidekiq/processor.rb +135 -83
- data/lib/sidekiq/rails.rb +42 -38
- data/lib/sidekiq/redis_connection.rb +49 -30
- data/lib/sidekiq/scheduled.rb +94 -31
- 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 +40 -31
- 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 +109 -74
- data/lib/sidekiq/web/csrf_protection.rb +180 -0
- data/lib/sidekiq/web/helpers.rb +117 -93
- data/lib/sidekiq/web/router.rb +23 -19
- data/lib/sidekiq/web.rb +61 -105
- data/lib/sidekiq/worker.rb +257 -99
- data/lib/sidekiq.rb +81 -46
- data/sidekiq.gemspec +23 -23
- 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 +77 -231
- data/web/assets/stylesheets/bootstrap.css +2 -2
- 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 +21 -5
- 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 +4 -2
- 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 -136
- 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 -216
- data/Gemfile +0 -8
- 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 -729
- 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,61 @@ 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
|
85
|
+
|
86
|
+
# Since the user can pass us a connection pool explicitly in the initializer, we
|
87
|
+
# need to verify the size is large enough or else Sidekiq's performance is dramatically slowed.
|
88
|
+
cursize = Sidekiq.redis_pool.size
|
89
|
+
needed = Sidekiq.options[:concurrency] + 2
|
90
|
+
raise "Your pool of #{cursize} Redis connections is too small, please increase the size to at least #{needed}" if cursize < needed
|
82
91
|
|
83
92
|
# cache process identity
|
84
93
|
Sidekiq.options[:identity] = identity
|
@@ -90,142 +99,123 @@ module Sidekiq
|
|
90
99
|
# Starting here the process will now have multiple threads running.
|
91
100
|
fire_event(:startup, reverse: false, reraise: true)
|
92
101
|
|
93
|
-
logger.debug { "Client Middleware: #{Sidekiq.client_middleware.map(&:klass).join(
|
94
|
-
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(", ")}" }
|
95
104
|
|
96
|
-
|
97
|
-
|
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"
|
98
111
|
end
|
99
112
|
|
100
|
-
require 'sidekiq/launcher'
|
101
113
|
@launcher = Sidekiq::Launcher.new(options)
|
102
114
|
|
103
115
|
begin
|
104
116
|
launcher.run
|
105
117
|
|
106
|
-
while readable_io =
|
107
|
-
signal = readable_io.
|
118
|
+
while (readable_io = self_read.wait_readable)
|
119
|
+
signal = readable_io.gets.strip
|
108
120
|
handle_signal(signal)
|
109
121
|
end
|
110
122
|
rescue Interrupt
|
111
|
-
logger.info
|
123
|
+
logger.info "Shutting down"
|
112
124
|
launcher.stop
|
113
|
-
# Explicitly exit so busy Processor threads can't block
|
114
|
-
# process shutdown.
|
115
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.
|
116
132
|
exit(0)
|
117
133
|
end
|
118
134
|
end
|
119
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
|
+
|
120
152
|
def self.banner
|
121
|
-
%
|
122
|
-
m,
|
123
|
-
`$b
|
124
|
-
.ss, $$: .,d$
|
125
|
-
`$$P,d$P' .,md$P"'
|
126
|
-
,$$$$$
|
127
|
-
.d
|
128
|
-
$$^' `"
|
129
|
-
$: ,$$:
|
130
|
-
`b :$$
|
131
|
-
$$:
|
132
|
-
$$ |____/|_
|
133
|
-
.d$$
|
134
|
-
}
|
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}}
|
135
167
|
end
|
136
168
|
|
137
169
|
SIGNAL_HANDLERS = {
|
138
170
|
# Ctrl-C in terminal
|
139
|
-
|
171
|
+
"INT" => ->(cli) { raise Interrupt },
|
140
172
|
# TERM is the signal that Sidekiq must exit.
|
141
173
|
# Heroku sends TERM and then waits 30 seconds for process to exit.
|
142
|
-
|
143
|
-
|
144
|
-
Sidekiq.logger.info "Received USR1, no longer accepting new work"
|
145
|
-
cli.launcher.quiet
|
146
|
-
},
|
147
|
-
'TSTP' => ->(cli) {
|
174
|
+
"TERM" => ->(cli) { raise Interrupt },
|
175
|
+
"TSTP" => ->(cli) {
|
148
176
|
Sidekiq.logger.info "Received TSTP, no longer accepting new work"
|
149
177
|
cli.launcher.quiet
|
150
178
|
},
|
151
|
-
|
152
|
-
if Sidekiq.options[:logfile]
|
153
|
-
Sidekiq.logger.info "Received USR2, reopening log file"
|
154
|
-
Sidekiq::Logging.reopen_logs
|
155
|
-
end
|
156
|
-
},
|
157
|
-
'TTIN' => ->(cli) {
|
179
|
+
"TTIN" => ->(cli) {
|
158
180
|
Thread.list.each do |thread|
|
159
|
-
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}"
|
160
182
|
if thread.backtrace
|
161
183
|
Sidekiq.logger.warn thread.backtrace.join("\n")
|
162
184
|
else
|
163
185
|
Sidekiq.logger.warn "<no backtrace available>"
|
164
186
|
end
|
165
187
|
end
|
166
|
-
}
|
188
|
+
}
|
167
189
|
}
|
190
|
+
UNHANDLED_SIGNAL_HANDLER = ->(cli) { Sidekiq.logger.info "No signal handler registered, ignoring" }
|
191
|
+
SIGNAL_HANDLERS.default = UNHANDLED_SIGNAL_HANDLER
|
168
192
|
|
169
193
|
def handle_signal(sig)
|
170
194
|
Sidekiq.logger.debug "Got #{sig} signal"
|
171
|
-
|
172
|
-
if handy
|
173
|
-
handy.call(self)
|
174
|
-
else
|
175
|
-
Sidekiq.logger.info { "No signal handler for #{sig}" }
|
176
|
-
end
|
195
|
+
SIGNAL_HANDLERS[sig].call(self)
|
177
196
|
end
|
178
197
|
|
179
198
|
private
|
180
199
|
|
181
200
|
def print_banner
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
puts Sidekiq::CLI.banner
|
186
|
-
puts "\e[0m"
|
187
|
-
end
|
188
|
-
end
|
189
|
-
|
190
|
-
def daemonize
|
191
|
-
return unless options[:daemon]
|
192
|
-
|
193
|
-
raise ArgumentError, "You really should set a logfile if you're going to daemonize" unless options[:logfile]
|
194
|
-
files_to_reopen = []
|
195
|
-
ObjectSpace.each_object(File) do |file|
|
196
|
-
files_to_reopen << file unless file.closed?
|
197
|
-
end
|
198
|
-
|
199
|
-
::Process.daemon(true, true)
|
200
|
-
|
201
|
-
files_to_reopen.each do |file|
|
202
|
-
begin
|
203
|
-
file.reopen file.path, "a+"
|
204
|
-
file.sync = true
|
205
|
-
rescue ::Exception
|
206
|
-
end
|
207
|
-
end
|
208
|
-
|
209
|
-
[$stdout, $stderr].each do |io|
|
210
|
-
File.open(options[:logfile], 'ab') do |f|
|
211
|
-
io.reopen(f)
|
212
|
-
end
|
213
|
-
io.sync = true
|
214
|
-
end
|
215
|
-
$stdin.reopen('/dev/null')
|
216
|
-
|
217
|
-
initialize_logger
|
201
|
+
puts "\e[31m"
|
202
|
+
puts Sidekiq::CLI.banner
|
203
|
+
puts "\e[0m"
|
218
204
|
end
|
219
205
|
|
220
206
|
def set_environment(cli_env)
|
221
|
-
|
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"
|
222
212
|
end
|
223
213
|
|
224
214
|
def symbolize_keys_deep!(hash)
|
225
215
|
hash.keys.each do |k|
|
226
216
|
symkey = k.respond_to?(:to_sym) ? k.to_sym : k
|
227
217
|
hash[symkey] = hash.delete k
|
228
|
-
symbolize_keys_deep! hash[symkey] if hash[symkey].
|
218
|
+
symbolize_keys_deep! hash[symkey] if hash[symkey].is_a? Hash
|
229
219
|
end
|
230
220
|
end
|
231
221
|
|
@@ -233,15 +223,37 @@ module Sidekiq
|
|
233
223
|
alias_method :☠, :exit
|
234
224
|
|
235
225
|
def setup_options(args)
|
226
|
+
# parse CLI options
|
236
227
|
opts = parse_options(args)
|
228
|
+
|
237
229
|
set_environment opts[:environment]
|
238
230
|
|
239
|
-
|
240
|
-
|
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
|
242
|
+
|
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]
|
241
251
|
|
242
|
-
|
243
|
-
opts[:
|
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"]
|
244
255
|
|
256
|
+
# merge with defaults
|
245
257
|
options.merge!(opts)
|
246
258
|
end
|
247
259
|
|
@@ -249,42 +261,29 @@ module Sidekiq
|
|
249
261
|
Sidekiq.options
|
250
262
|
end
|
251
263
|
|
252
|
-
def
|
253
|
-
ENV[
|
254
|
-
|
255
|
-
raise ArgumentError, "#{options[:require]} does not exist" unless File.exist?(options[:require])
|
264
|
+
def boot_application
|
265
|
+
ENV["RACK_ENV"] = ENV["RAILS_ENV"] = environment
|
256
266
|
|
257
267
|
if File.directory?(options[:require])
|
258
|
-
require
|
259
|
-
if ::Rails::VERSION::MAJOR <
|
268
|
+
require "rails"
|
269
|
+
if ::Rails::VERSION::MAJOR < 5
|
260
270
|
raise "Sidekiq no longer supports this version of Rails"
|
261
|
-
elsif ::Rails::VERSION::MAJOR == 4
|
262
|
-
# Painful contortions, see 1791 for discussion
|
263
|
-
# No autoloading, we want to force eager load for everything.
|
264
|
-
require File.expand_path("#{options[:require]}/config/application.rb")
|
265
|
-
::Rails::Application.initializer "sidekiq.eager_load" do
|
266
|
-
::Rails.application.config.eager_load = true
|
267
|
-
end
|
268
|
-
require 'sidekiq/rails'
|
269
|
-
require File.expand_path("#{options[:require]}/config/environment.rb")
|
270
271
|
else
|
271
|
-
require
|
272
|
+
require "sidekiq/rails"
|
272
273
|
require File.expand_path("#{options[:require]}/config/environment.rb")
|
273
274
|
end
|
274
275
|
options[:tag] ||= default_tag
|
275
276
|
else
|
276
|
-
|
277
|
-
"./#{options[:require]} or /path/to/#{options[:require]}"
|
278
|
-
|
279
|
-
require(options[:require]) || raise(ArgumentError, not_required_message)
|
277
|
+
require options[:require]
|
280
278
|
end
|
281
279
|
end
|
282
280
|
|
283
281
|
def default_tag
|
284
282
|
dir = ::Rails.root
|
285
283
|
name = File.basename(dir)
|
286
|
-
|
287
|
-
|
284
|
+
prevdir = File.dirname(dir) # Capistrano release directory?
|
285
|
+
if name.to_i != 0 && prevdir
|
286
|
+
if File.basename(prevdir) == "releases"
|
288
287
|
return File.basename(File.dirname(prevdir))
|
289
288
|
end
|
290
289
|
end
|
@@ -292,12 +291,10 @@ module Sidekiq
|
|
292
291
|
end
|
293
292
|
|
294
293
|
def validate!
|
295
|
-
options[:queues] << 'default' if options[:queues].empty?
|
296
|
-
|
297
294
|
if !File.exist?(options[:require]) ||
|
298
|
-
|
295
|
+
(File.directory?(options[:require]) && !File.exist?("#{options[:require]}/config/application.rb"))
|
299
296
|
logger.info "=================================================================="
|
300
|
-
logger.info " Please point
|
297
|
+
logger.info " Please point Sidekiq to a Rails application or a Ruby file "
|
301
298
|
logger.info " to load your worker classes with -r [DIR|FILE]."
|
302
299
|
logger.info "=================================================================="
|
303
300
|
logger.info @parser
|
@@ -305,46 +302,45 @@ module Sidekiq
|
|
305
302
|
end
|
306
303
|
|
307
304
|
[:concurrency, :timeout].each do |opt|
|
308
|
-
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
|
309
306
|
end
|
310
307
|
end
|
311
308
|
|
312
309
|
def parse_options(argv)
|
313
310
|
opts = {}
|
311
|
+
@parser = option_parser(opts)
|
312
|
+
@parser.parse!(argv)
|
313
|
+
opts
|
314
|
+
end
|
314
315
|
|
315
|
-
|
316
|
-
|
316
|
+
def option_parser(opts)
|
317
|
+
parser = OptionParser.new { |o|
|
318
|
+
o.on "-c", "--concurrency INT", "processor threads to use" do |arg|
|
317
319
|
opts[:concurrency] = Integer(arg)
|
318
320
|
end
|
319
321
|
|
320
|
-
o.on
|
321
|
-
|
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"
|
322
324
|
end
|
323
325
|
|
324
|
-
o.on
|
326
|
+
o.on "-e", "--environment ENV", "Application environment" do |arg|
|
325
327
|
opts[:environment] = arg
|
326
328
|
end
|
327
329
|
|
328
|
-
o.on
|
330
|
+
o.on "-g", "--tag TAG", "Process tag for procline" do |arg|
|
329
331
|
opts[:tag] = arg
|
330
332
|
end
|
331
333
|
|
332
|
-
# this index remains here for backwards compatibility but none of the Sidekiq
|
333
|
-
# family use this value anymore. it was used by Pro's original reliable_fetch.
|
334
|
-
o.on '-i', '--index INT', "unique process index on this machine" do |arg|
|
335
|
-
opts[:index] = Integer(arg.match(/\d+/)[0])
|
336
|
-
end
|
337
|
-
|
338
334
|
o.on "-q", "--queue QUEUE[,WEIGHT]", "Queues to process with optional weights" do |arg|
|
339
335
|
queue, weight = arg.split(",")
|
340
336
|
parse_queue opts, queue, weight
|
341
337
|
end
|
342
338
|
|
343
|
-
o.on
|
339
|
+
o.on "-r", "--require [PATH|DIR]", "Location of Rails application with workers or file to require" do |arg|
|
344
340
|
opts[:require] = arg
|
345
341
|
end
|
346
342
|
|
347
|
-
o.on
|
343
|
+
o.on "-t", "--timeout NUM", "Shutdown timeout" do |arg|
|
348
344
|
opts[:timeout] = Integer(arg)
|
349
345
|
end
|
350
346
|
|
@@ -352,88 +348,80 @@ module Sidekiq
|
|
352
348
|
opts[:verbose] = arg
|
353
349
|
end
|
354
350
|
|
355
|
-
o.on
|
351
|
+
o.on "-C", "--config PATH", "path to YAML config file" do |arg|
|
356
352
|
opts[:config_file] = arg
|
357
353
|
end
|
358
354
|
|
359
|
-
o.on
|
360
|
-
|
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"
|
361
357
|
end
|
362
358
|
|
363
|
-
o.on
|
364
|
-
|
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"
|
365
361
|
end
|
366
362
|
|
367
|
-
o.on
|
363
|
+
o.on "-V", "--version", "Print version and exit" do |arg|
|
368
364
|
puts "Sidekiq #{Sidekiq::VERSION}"
|
369
365
|
die(0)
|
370
366
|
end
|
371
|
-
|
367
|
+
}
|
372
368
|
|
373
|
-
|
374
|
-
|
375
|
-
logger.info
|
369
|
+
parser.banner = "sidekiq [options]"
|
370
|
+
parser.on_tail "-h", "--help", "Show help" do
|
371
|
+
logger.info parser
|
376
372
|
die 1
|
377
373
|
end
|
378
|
-
@parser.parse!(argv)
|
379
|
-
|
380
|
-
%w[config/sidekiq.yml config/sidekiq.yml.erb].each do |filename|
|
381
|
-
opts[:config_file] ||= filename if File.exist?(filename)
|
382
|
-
end
|
383
374
|
|
384
|
-
|
375
|
+
parser
|
385
376
|
end
|
386
377
|
|
387
378
|
def initialize_logger
|
388
|
-
Sidekiq::Logging.initialize_logger(options[:logfile]) if options[:logfile]
|
389
|
-
|
390
379
|
Sidekiq.logger.level = ::Logger::DEBUG if options[:verbose]
|
391
380
|
end
|
392
381
|
|
393
|
-
def
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
382
|
+
def parse_config(path)
|
383
|
+
erb = ERB.new(File.read(path))
|
384
|
+
erb.filename = File.expand_path(path)
|
385
|
+
opts = load_yaml(erb.result) || {}
|
386
|
+
|
387
|
+
if opts.respond_to? :deep_symbolize_keys!
|
388
|
+
opts.deep_symbolize_keys!
|
389
|
+
else
|
390
|
+
symbolize_keys_deep!(opts)
|
399
391
|
end
|
400
|
-
end
|
401
392
|
|
402
|
-
|
403
|
-
opts
|
404
|
-
if File.exist?(cfile)
|
405
|
-
opts = YAML.load(ERB.new(IO.read(cfile)).result) || opts
|
393
|
+
opts = opts.merge(opts.delete(environment.to_sym) || {})
|
394
|
+
opts.delete(:strict)
|
406
395
|
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
end
|
396
|
+
parse_queues(opts, opts.delete(:queues) || [])
|
397
|
+
|
398
|
+
opts
|
399
|
+
end
|
412
400
|
|
413
|
-
|
414
|
-
|
401
|
+
def load_yaml(src)
|
402
|
+
if Psych::VERSION > "4.0"
|
403
|
+
YAML.safe_load(src, permitted_classes: [Symbol], aliases: true)
|
415
404
|
else
|
416
|
-
|
417
|
-
# can be deployed by cap with just the defaults.
|
418
|
-
end
|
419
|
-
ns = opts.delete(:namespace)
|
420
|
-
if ns
|
421
|
-
# logger hasn't been initialized yet, puts is all we have.
|
422
|
-
puts("namespace should be set in your ruby initializer, is ignored in config file")
|
423
|
-
puts("config.redis = { :url => ..., :namespace => '#{ns}' }")
|
405
|
+
YAML.load(src)
|
424
406
|
end
|
425
|
-
opts
|
426
407
|
end
|
427
408
|
|
428
409
|
def parse_queues(opts, queues_and_weights)
|
429
410
|
queues_and_weights.each { |queue_and_weight| parse_queue(opts, *queue_and_weight) }
|
430
411
|
end
|
431
412
|
|
432
|
-
def parse_queue(opts,
|
433
|
-
[
|
434
|
-
|
435
|
-
|
413
|
+
def parse_queue(opts, queue, weight = nil)
|
414
|
+
opts[:queues] ||= []
|
415
|
+
opts[:strict] = true if opts[:strict].nil?
|
416
|
+
raise ArgumentError, "queues: #{queue} cannot be defined twice" if opts[:queues].include?(queue)
|
417
|
+
[weight.to_i, 1].max.times { opts[:queues] << queue.to_s }
|
436
418
|
opts[:strict] = false if weight.to_i > 0
|
437
419
|
end
|
420
|
+
|
421
|
+
def rails_app?
|
422
|
+
defined?(::Rails) && ::Rails.respond_to?(:application)
|
423
|
+
end
|
438
424
|
end
|
439
425
|
end
|
426
|
+
|
427
|
+
require "sidekiq/systemd"
|