sidekiq 4.2.4 → 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 +523 -0
- data/LICENSE +3 -3
- data/README.md +23 -36
- data/bin/sidekiq +26 -2
- data/bin/sidekiqload +28 -38
- 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/job_spec.rb.erb +6 -0
- data/lib/generators/sidekiq/templates/job_test.rb.erb +8 -0
- data/lib/sidekiq/api.rb +403 -243
- data/lib/sidekiq/cli.rb +230 -211
- data/lib/sidekiq/client.rb +53 -64
- data/lib/sidekiq/delay.rb +43 -0
- data/lib/sidekiq/exception_handler.rb +12 -16
- 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 +14 -6
- data/lib/sidekiq/fetch.rb +39 -31
- data/lib/sidekiq/job.rb +13 -0
- data/lib/sidekiq/job_logger.rb +63 -0
- data/lib/sidekiq/job_retry.rb +261 -0
- data/lib/sidekiq/job_util.rb +65 -0
- data/lib/sidekiq/launcher.rb +170 -71
- data/lib/sidekiq/logger.rb +166 -0
- data/lib/sidekiq/manager.rb +21 -26
- 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 +161 -70
- data/lib/sidekiq/rails.rb +41 -73
- data/lib/sidekiq/redis_connection.rb +65 -20
- data/lib/sidekiq/scheduled.rb +95 -34
- 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 +52 -26
- data/lib/sidekiq/util.rb +60 -14
- data/lib/sidekiq/version.rb +2 -1
- data/lib/sidekiq/web/action.rb +15 -15
- data/lib/sidekiq/web/application.rb +115 -89
- data/lib/sidekiq/web/csrf_protection.rb +180 -0
- data/lib/sidekiq/web/helpers.rb +151 -83
- data/lib/sidekiq/web/router.rb +27 -19
- data/lib/sidekiq/web.rb +65 -109
- data/lib/sidekiq/worker.rb +284 -41
- data/lib/sidekiq.rb +93 -60
- data/sidekiq.gemspec +24 -22
- data/web/assets/images/apple-touch-icon.png +0 -0
- data/web/assets/javascripts/application.js +83 -64
- data/web/assets/javascripts/dashboard.js +81 -85
- data/web/assets/stylesheets/application-dark.css +143 -0
- data/web/assets/stylesheets/application-rtl.css +242 -0
- data/web/assets/stylesheets/application.css +319 -143
- data/web/assets/stylesheets/bootstrap-rtl.min.css +9 -0
- data/web/assets/stylesheets/bootstrap.css +2 -2
- data/web/locales/ar.yml +87 -0
- data/web/locales/de.yml +14 -2
- data/web/locales/en.yml +8 -1
- data/web/locales/es.yml +22 -5
- data/web/locales/fa.yml +80 -0
- data/web/locales/fr.yml +10 -3
- data/web/locales/he.yml +79 -0
- data/web/locales/ja.yml +12 -4
- data/web/locales/lt.yml +83 -0
- data/web/locales/pl.yml +4 -4
- data/web/locales/ru.yml +4 -0
- data/web/locales/ur.yml +80 -0
- data/web/locales/vi.yml +83 -0
- data/web/views/_footer.erb +5 -2
- data/web/views/_job_info.erb +4 -3
- data/web/views/_nav.erb +4 -18
- data/web/views/_paging.erb +1 -1
- data/web/views/_poll_link.erb +2 -5
- data/web/views/_summary.erb +7 -7
- data/web/views/busy.erb +60 -22
- data/web/views/dashboard.erb +23 -15
- data/web/views/dead.erb +3 -3
- data/web/views/layout.erb +14 -3
- data/web/views/morgue.erb +19 -12
- data/web/views/queue.erb +24 -14
- data/web/views/queues.erb +14 -4
- data/web/views/retries.erb +22 -13
- data/web/views/retry.erb +4 -4
- data/web/views/scheduled.erb +7 -4
- metadata +49 -198
- data/.github/contributing.md +0 -32
- data/.github/issue_template.md +0 -4
- data/.gitignore +0 -12
- data/.travis.yml +0 -12
- data/3.0-Upgrade.md +0 -70
- data/4.0-Upgrade.md +0 -53
- data/COMM-LICENSE +0 -95
- data/Ent-Changes.md +0 -146
- data/Gemfile +0 -29
- data/Pro-2.0-Upgrade.md +0 -138
- data/Pro-3.0-Upgrade.md +0 -44
- data/Pro-Changes.md +0 -585
- data/Rakefile +0 -9
- data/bin/sidekiqctl +0 -99
- data/code_of_conduct.md +0 -50
- data/lib/generators/sidekiq/templates/worker_spec.rb.erb +0 -6
- data/lib/generators/sidekiq/templates/worker_test.rb.erb +0 -8
- data/lib/generators/sidekiq/worker_generator.rb +0 -49
- data/lib/sidekiq/core_ext.rb +0 -106
- data/lib/sidekiq/logging.rb +0 -106
- data/lib/sidekiq/middleware/server/active_record.rb +0 -13
- data/lib/sidekiq/middleware/server/logging.rb +0 -40
- data/lib/sidekiq/middleware/server/retry_jobs.rb +0 -205
- data/test/config.yml +0 -9
- data/test/env_based_config.yml +0 -11
- data/test/fake_env.rb +0 -1
- data/test/fixtures/en.yml +0 -2
- data/test/helper.rb +0 -75
- data/test/test_actors.rb +0 -138
- data/test/test_api.rb +0 -528
- data/test/test_cli.rb +0 -418
- data/test/test_client.rb +0 -266
- data/test/test_exception_handler.rb +0 -56
- data/test/test_extensions.rb +0 -127
- data/test/test_fetch.rb +0 -50
- data/test/test_launcher.rb +0 -95
- data/test/test_logging.rb +0 -35
- data/test/test_manager.rb +0 -50
- data/test/test_middleware.rb +0 -158
- data/test/test_processor.rb +0 -235
- data/test/test_rails.rb +0 -22
- data/test/test_redis_connection.rb +0 -132
- data/test/test_retry.rb +0 -326
- data/test/test_retry_exhausted.rb +0 -149
- data/test/test_scheduled.rb +0 -115
- data/test/test_scheduling.rb +0 -58
- data/test/test_sidekiq.rb +0 -107
- data/test/test_testing.rb +0 -143
- data/test/test_testing_fake.rb +0 -357
- data/test/test_testing_inline.rb +0 -94
- data/test/test_util.rb +0 -13
- data/test/test_web.rb +0 -726
- data/test/test_web_helpers.rb +0 -54
data/lib/sidekiq/cli.rb
CHANGED
@@ -1,216 +1,259 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
|
2
|
+
|
3
3
|
$stdout.sync = true
|
4
4
|
|
5
|
-
require
|
6
|
-
require
|
7
|
-
require
|
8
|
-
require
|
9
|
-
require
|
5
|
+
require "yaml"
|
6
|
+
require "singleton"
|
7
|
+
require "optparse"
|
8
|
+
require "erb"
|
9
|
+
require "fileutils"
|
10
10
|
|
11
|
-
require
|
12
|
-
require
|
11
|
+
require "sidekiq"
|
12
|
+
require "sidekiq/launcher"
|
13
|
+
require "sidekiq/util"
|
13
14
|
|
14
15
|
module Sidekiq
|
15
16
|
class CLI
|
16
17
|
include Util
|
17
18
|
include Singleton unless $TESTING
|
18
19
|
|
19
|
-
PROCTITLES = [
|
20
|
-
proc { 'sidekiq'.freeze },
|
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
|
-
]
|
26
|
-
|
27
|
-
# Used for CLI testing
|
28
|
-
attr_accessor :code
|
29
20
|
attr_accessor :launcher
|
30
21
|
attr_accessor :environment
|
31
22
|
|
32
|
-
def
|
33
|
-
@code = nil
|
34
|
-
end
|
35
|
-
|
36
|
-
def parse(args=ARGV)
|
37
|
-
@code = nil
|
38
|
-
|
23
|
+
def parse(args = ARGV)
|
39
24
|
setup_options(args)
|
40
25
|
initialize_logger
|
41
26
|
validate!
|
42
|
-
|
43
|
-
|
27
|
+
end
|
28
|
+
|
29
|
+
def jruby?
|
30
|
+
defined?(::JRUBY_VERSION)
|
44
31
|
end
|
45
32
|
|
46
33
|
# Code within this method is not tested because it alters
|
47
34
|
# global process state irreversibly. PRs which improve the
|
48
35
|
# test coverage of Sidekiq::CLI are welcomed.
|
49
|
-
def run
|
50
|
-
|
51
|
-
print_banner
|
36
|
+
def run(boot_app: true)
|
37
|
+
boot_application if boot_app
|
52
38
|
|
53
|
-
|
39
|
+
if environment == "development" && $stdout.tty? && Sidekiq.log_formatter.is_a?(Sidekiq::Logger::Formatters::Pretty)
|
40
|
+
print_banner
|
41
|
+
end
|
42
|
+
logger.info "Booted Rails #{::Rails.version} application in #{environment} environment" if rails_app?
|
54
43
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
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?
|
48
|
+
sigs.each do |sig|
|
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
|
59
57
|
end
|
60
|
-
|
61
|
-
puts "Signal #{sig} not supported"
|
58
|
+
self_write.puts(sig)
|
62
59
|
end
|
60
|
+
rescue ArgumentError
|
61
|
+
puts "Signal #{sig} not supported"
|
63
62
|
end
|
64
63
|
|
65
64
|
logger.info "Running in #{RUBY_DESCRIPTION}"
|
66
65
|
logger.info Sidekiq::LICENSE
|
67
|
-
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)
|
68
67
|
|
69
68
|
# touch the connection pool so it is created before we
|
70
69
|
# fire startup and start multithreading.
|
71
|
-
|
72
|
-
|
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
|
91
|
+
|
92
|
+
# cache process identity
|
93
|
+
Sidekiq.options[:identity] = identity
|
73
94
|
|
74
95
|
# Touch middleware so it isn't lazy loaded by multiple threads, #3043
|
75
96
|
Sidekiq.server_middleware
|
76
97
|
|
77
98
|
# Before this point, the process is initializing with just the main thread.
|
78
99
|
# Starting here the process will now have multiple threads running.
|
79
|
-
fire_event(:startup)
|
100
|
+
fire_event(:startup, reverse: false, reraise: true)
|
80
101
|
|
81
|
-
logger.debug { "Client Middleware: #{Sidekiq.client_middleware.map(&:klass).join(
|
82
|
-
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(", ")}" }
|
83
104
|
|
84
|
-
|
85
|
-
|
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"
|
86
111
|
end
|
87
112
|
|
88
|
-
require 'sidekiq/launcher'
|
89
113
|
@launcher = Sidekiq::Launcher.new(options)
|
90
114
|
|
91
115
|
begin
|
92
116
|
launcher.run
|
93
117
|
|
94
|
-
while readable_io = IO.select([self_read])
|
118
|
+
while (readable_io = IO.select([self_read]))
|
95
119
|
signal = readable_io.first[0].gets.strip
|
96
120
|
handle_signal(signal)
|
97
121
|
end
|
98
122
|
rescue Interrupt
|
99
|
-
logger.info
|
123
|
+
logger.info "Shutting down"
|
100
124
|
launcher.stop
|
101
|
-
# Explicitly exit so busy Processor threads can't block
|
102
|
-
# process shutdown.
|
103
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.
|
104
132
|
exit(0)
|
105
133
|
end
|
106
134
|
end
|
107
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
|
+
|
108
152
|
def self.banner
|
109
|
-
%
|
110
|
-
m,
|
111
|
-
`$b
|
112
|
-
.ss, $$: .,d$
|
113
|
-
`$$P,d$P' .,md$P"'
|
114
|
-
,$$$$$
|
115
|
-
.d
|
116
|
-
$$^' `"
|
117
|
-
$: ,$$:
|
118
|
-
`b :$$
|
119
|
-
$$:
|
120
|
-
$$ |____/|_
|
121
|
-
.d$$
|
122
|
-
}
|
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}}
|
123
167
|
end
|
124
168
|
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
Sidekiq.logger.info "Received USR1, no longer accepting new work"
|
137
|
-
launcher.quiet
|
138
|
-
when 'USR2'
|
139
|
-
if Sidekiq.options[:logfile]
|
140
|
-
Sidekiq.logger.info "Received USR2, reopening log file"
|
141
|
-
Sidekiq::Logging.reopen_logs
|
142
|
-
end
|
143
|
-
when 'TTIN'
|
169
|
+
SIGNAL_HANDLERS = {
|
170
|
+
# Ctrl-C in terminal
|
171
|
+
"INT" => ->(cli) { raise Interrupt },
|
172
|
+
# TERM is the signal that Sidekiq must exit.
|
173
|
+
# Heroku sends TERM and then waits 30 seconds for process to exit.
|
174
|
+
"TERM" => ->(cli) { raise Interrupt },
|
175
|
+
"TSTP" => ->(cli) {
|
176
|
+
Sidekiq.logger.info "Received TSTP, no longer accepting new work"
|
177
|
+
cli.launcher.quiet
|
178
|
+
},
|
179
|
+
"TTIN" => ->(cli) {
|
144
180
|
Thread.list.each do |thread|
|
145
|
-
Sidekiq.logger.warn "Thread TID-#{thread.object_id.to_s(36)} #{thread
|
181
|
+
Sidekiq.logger.warn "Thread TID-#{(thread.object_id ^ ::Process.pid).to_s(36)} #{thread.name}"
|
146
182
|
if thread.backtrace
|
147
183
|
Sidekiq.logger.warn thread.backtrace.join("\n")
|
148
184
|
else
|
149
185
|
Sidekiq.logger.warn "<no backtrace available>"
|
150
186
|
end
|
151
187
|
end
|
152
|
-
|
188
|
+
}
|
189
|
+
}
|
190
|
+
UNHANDLED_SIGNAL_HANDLER = ->(cli) { Sidekiq.logger.info "No signal handler registered, ignoring" }
|
191
|
+
SIGNAL_HANDLERS.default = UNHANDLED_SIGNAL_HANDLER
|
192
|
+
|
193
|
+
def handle_signal(sig)
|
194
|
+
Sidekiq.logger.debug "Got #{sig} signal"
|
195
|
+
SIGNAL_HANDLERS[sig].call(self)
|
153
196
|
end
|
154
197
|
|
155
198
|
private
|
156
199
|
|
157
200
|
def print_banner
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
puts Sidekiq::CLI.banner
|
162
|
-
puts "\e[0m"
|
163
|
-
end
|
201
|
+
puts "\e[31m"
|
202
|
+
puts Sidekiq::CLI.banner
|
203
|
+
puts "\e[0m"
|
164
204
|
end
|
165
205
|
|
166
|
-
def
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
files_to_reopen << file unless file.closed?
|
173
|
-
end
|
174
|
-
|
175
|
-
::Process.daemon(true, true)
|
176
|
-
|
177
|
-
files_to_reopen.each do |file|
|
178
|
-
begin
|
179
|
-
file.reopen file.path, "a+"
|
180
|
-
file.sync = true
|
181
|
-
rescue ::Exception
|
182
|
-
end
|
183
|
-
end
|
184
|
-
|
185
|
-
[$stdout, $stderr].each do |io|
|
186
|
-
File.open(options[:logfile], 'ab') do |f|
|
187
|
-
io.reopen(f)
|
188
|
-
end
|
189
|
-
io.sync = true
|
190
|
-
end
|
191
|
-
$stdin.reopen('/dev/null')
|
192
|
-
|
193
|
-
initialize_logger
|
206
|
+
def set_environment(cli_env)
|
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"
|
194
212
|
end
|
195
213
|
|
196
|
-
def
|
197
|
-
|
214
|
+
def symbolize_keys_deep!(hash)
|
215
|
+
hash.keys.each do |k|
|
216
|
+
symkey = k.respond_to?(:to_sym) ? k.to_sym : k
|
217
|
+
hash[symkey] = hash.delete k
|
218
|
+
symbolize_keys_deep! hash[symkey] if hash[symkey].is_a? Hash
|
219
|
+
end
|
198
220
|
end
|
199
221
|
|
200
222
|
alias_method :die, :exit
|
201
223
|
alias_method :☠, :exit
|
202
224
|
|
203
225
|
def setup_options(args)
|
226
|
+
# parse CLI options
|
204
227
|
opts = parse_options(args)
|
228
|
+
|
205
229
|
set_environment opts[:environment]
|
206
230
|
|
207
|
-
|
208
|
-
|
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
|
209
242
|
|
210
|
-
|
211
|
-
|
212
|
-
|
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
|
213
248
|
|
249
|
+
# parse config file options
|
250
|
+
opts = parse_config(opts[:config_file]).merge(opts) if opts[:config_file]
|
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
|
214
257
|
options.merge!(opts)
|
215
258
|
end
|
216
259
|
|
@@ -218,43 +261,29 @@ module Sidekiq
|
|
218
261
|
Sidekiq.options
|
219
262
|
end
|
220
263
|
|
221
|
-
def
|
222
|
-
ENV[
|
223
|
-
|
224
|
-
raise ArgumentError, "#{options[:require]} does not exist" unless File.exist?(options[:require])
|
264
|
+
def boot_application
|
265
|
+
ENV["RACK_ENV"] = ENV["RAILS_ENV"] = environment
|
225
266
|
|
226
267
|
if File.directory?(options[:require])
|
227
|
-
require
|
228
|
-
if ::Rails::VERSION::MAJOR <
|
229
|
-
|
230
|
-
require File.expand_path("#{options[:require]}/config/environment.rb")
|
231
|
-
::Rails.application.eager_load!
|
232
|
-
elsif ::Rails::VERSION::MAJOR == 4
|
233
|
-
# Painful contortions, see 1791 for discussion
|
234
|
-
require File.expand_path("#{options[:require]}/config/application.rb")
|
235
|
-
::Rails::Application.initializer "sidekiq.eager_load" do
|
236
|
-
::Rails.application.config.eager_load = true
|
237
|
-
end
|
238
|
-
require 'sidekiq/rails'
|
239
|
-
require File.expand_path("#{options[:require]}/config/environment.rb")
|
268
|
+
require "rails"
|
269
|
+
if ::Rails::VERSION::MAJOR < 5
|
270
|
+
raise "Sidekiq no longer supports this version of Rails"
|
240
271
|
else
|
241
|
-
require
|
272
|
+
require "sidekiq/rails"
|
242
273
|
require File.expand_path("#{options[:require]}/config/environment.rb")
|
243
274
|
end
|
244
275
|
options[:tag] ||= default_tag
|
245
276
|
else
|
246
|
-
|
247
|
-
"./#{options[:require]} or /path/to/#{options[:require]}"
|
248
|
-
|
249
|
-
require(options[:require]) || raise(ArgumentError, not_required_message)
|
277
|
+
require options[:require]
|
250
278
|
end
|
251
279
|
end
|
252
280
|
|
253
281
|
def default_tag
|
254
282
|
dir = ::Rails.root
|
255
283
|
name = File.basename(dir)
|
256
|
-
|
257
|
-
|
284
|
+
prevdir = File.dirname(dir) # Capistrano release directory?
|
285
|
+
if name.to_i != 0 && prevdir
|
286
|
+
if File.basename(prevdir) == "releases"
|
258
287
|
return File.basename(File.dirname(prevdir))
|
259
288
|
end
|
260
289
|
end
|
@@ -262,12 +291,10 @@ module Sidekiq
|
|
262
291
|
end
|
263
292
|
|
264
293
|
def validate!
|
265
|
-
options[:queues] << 'default' if options[:queues].empty?
|
266
|
-
|
267
294
|
if !File.exist?(options[:require]) ||
|
268
|
-
|
295
|
+
(File.directory?(options[:require]) && !File.exist?("#{options[:require]}/config/application.rb"))
|
269
296
|
logger.info "=================================================================="
|
270
|
-
logger.info " Please point
|
297
|
+
logger.info " Please point Sidekiq to a Rails application or a Ruby file "
|
271
298
|
logger.info " to load your worker classes with -r [DIR|FILE]."
|
272
299
|
logger.info "=================================================================="
|
273
300
|
logger.info @parser
|
@@ -275,44 +302,45 @@ module Sidekiq
|
|
275
302
|
end
|
276
303
|
|
277
304
|
[:concurrency, :timeout].each do |opt|
|
278
|
-
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
|
279
306
|
end
|
280
307
|
end
|
281
308
|
|
282
309
|
def parse_options(argv)
|
283
310
|
opts = {}
|
311
|
+
@parser = option_parser(opts)
|
312
|
+
@parser.parse!(argv)
|
313
|
+
opts
|
314
|
+
end
|
284
315
|
|
285
|
-
|
286
|
-
|
316
|
+
def option_parser(opts)
|
317
|
+
parser = OptionParser.new { |o|
|
318
|
+
o.on "-c", "--concurrency INT", "processor threads to use" do |arg|
|
287
319
|
opts[:concurrency] = Integer(arg)
|
288
320
|
end
|
289
321
|
|
290
|
-
o.on
|
291
|
-
|
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"
|
292
324
|
end
|
293
325
|
|
294
|
-
o.on
|
326
|
+
o.on "-e", "--environment ENV", "Application environment" do |arg|
|
295
327
|
opts[:environment] = arg
|
296
328
|
end
|
297
329
|
|
298
|
-
o.on
|
330
|
+
o.on "-g", "--tag TAG", "Process tag for procline" do |arg|
|
299
331
|
opts[:tag] = arg
|
300
332
|
end
|
301
333
|
|
302
|
-
o.on '-i', '--index INT', "unique process index on this machine" do |arg|
|
303
|
-
opts[:index] = Integer(arg.match(/\d+/)[0])
|
304
|
-
end
|
305
|
-
|
306
334
|
o.on "-q", "--queue QUEUE[,WEIGHT]", "Queues to process with optional weights" do |arg|
|
307
335
|
queue, weight = arg.split(",")
|
308
336
|
parse_queue opts, queue, weight
|
309
337
|
end
|
310
338
|
|
311
|
-
o.on
|
339
|
+
o.on "-r", "--require [PATH|DIR]", "Location of Rails application with workers or file to require" do |arg|
|
312
340
|
opts[:require] = arg
|
313
341
|
end
|
314
342
|
|
315
|
-
o.on
|
343
|
+
o.on "-t", "--timeout NUM", "Shutdown timeout" do |arg|
|
316
344
|
opts[:timeout] = Integer(arg)
|
317
345
|
end
|
318
346
|
|
@@ -320,69 +348,53 @@ module Sidekiq
|
|
320
348
|
opts[:verbose] = arg
|
321
349
|
end
|
322
350
|
|
323
|
-
o.on
|
351
|
+
o.on "-C", "--config PATH", "path to YAML config file" do |arg|
|
324
352
|
opts[:config_file] = arg
|
325
353
|
end
|
326
354
|
|
327
|
-
o.on
|
328
|
-
|
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"
|
329
357
|
end
|
330
358
|
|
331
|
-
o.on
|
332
|
-
|
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"
|
333
361
|
end
|
334
362
|
|
335
|
-
o.on
|
363
|
+
o.on "-V", "--version", "Print version and exit" do |arg|
|
336
364
|
puts "Sidekiq #{Sidekiq::VERSION}"
|
337
365
|
die(0)
|
338
366
|
end
|
339
|
-
|
367
|
+
}
|
340
368
|
|
341
|
-
|
342
|
-
|
343
|
-
logger.info
|
369
|
+
parser.banner = "sidekiq [options]"
|
370
|
+
parser.on_tail "-h", "--help", "Show help" do
|
371
|
+
logger.info parser
|
344
372
|
die 1
|
345
373
|
end
|
346
|
-
@parser.parse!(argv)
|
347
374
|
|
348
|
-
|
349
|
-
opts[:config_file] ||= filename if File.exist?(filename)
|
350
|
-
end
|
351
|
-
|
352
|
-
opts
|
375
|
+
parser
|
353
376
|
end
|
354
377
|
|
355
378
|
def initialize_logger
|
356
|
-
Sidekiq::Logging.initialize_logger(options[:logfile]) if options[:logfile]
|
357
|
-
|
358
379
|
Sidekiq.logger.level = ::Logger::DEBUG if options[:verbose]
|
359
380
|
end
|
360
381
|
|
361
|
-
def
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
f.puts ::Process.pid
|
366
|
-
end
|
367
|
-
end
|
368
|
-
end
|
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) || {}
|
369
386
|
|
370
|
-
|
371
|
-
|
372
|
-
if File.exist?(cfile)
|
373
|
-
opts = YAML.load(ERB.new(IO.read(cfile)).result) || opts
|
374
|
-
opts = opts.merge(opts.delete(environment) || {})
|
375
|
-
parse_queues(opts, opts.delete(:queues) || [])
|
387
|
+
if opts.respond_to? :deep_symbolize_keys!
|
388
|
+
opts.deep_symbolize_keys!
|
376
389
|
else
|
377
|
-
|
378
|
-
# can be deployed by cap with just the defaults.
|
379
|
-
end
|
380
|
-
ns = opts.delete(:namespace)
|
381
|
-
if ns
|
382
|
-
# logger hasn't been initialized yet, puts is all we have.
|
383
|
-
puts("namespace should be set in your ruby initializer, is ignored in config file")
|
384
|
-
puts("config.redis = { :url => ..., :namespace => '#{ns}' }")
|
390
|
+
symbolize_keys_deep!(opts)
|
385
391
|
end
|
392
|
+
|
393
|
+
opts = opts.merge(opts.delete(environment.to_sym) || {})
|
394
|
+
opts.delete(:strict)
|
395
|
+
|
396
|
+
parse_queues(opts, opts.delete(:queues) || [])
|
397
|
+
|
386
398
|
opts
|
387
399
|
end
|
388
400
|
|
@@ -390,11 +402,18 @@ module Sidekiq
|
|
390
402
|
queues_and_weights.each { |queue_and_weight| parse_queue(opts, *queue_and_weight) }
|
391
403
|
end
|
392
404
|
|
393
|
-
def parse_queue(opts,
|
394
|
-
[
|
395
|
-
|
396
|
-
|
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 }
|
397
410
|
opts[:strict] = false if weight.to_i > 0
|
398
411
|
end
|
412
|
+
|
413
|
+
def rails_app?
|
414
|
+
defined?(::Rails) && ::Rails.respond_to?(:application)
|
415
|
+
end
|
399
416
|
end
|
400
417
|
end
|
418
|
+
|
419
|
+
require "sidekiq/systemd"
|