sidekiq 4.2.2 → 6.3.1
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 +5 -5
- data/Changes.md +516 -0
- data/LICENSE +2 -2
- data/README.md +23 -36
- data/bin/sidekiq +26 -2
- data/bin/sidekiqload +28 -38
- data/bin/sidekiqmon +8 -0
- data/lib/generators/sidekiq/templates/worker_spec.rb.erb +1 -1
- data/lib/generators/sidekiq/templates/worker_test.rb.erb +2 -2
- data/lib/generators/sidekiq/worker_generator.rb +21 -13
- data/lib/sidekiq/api.rb +401 -243
- data/lib/sidekiq/cli.rb +228 -212
- data/lib/sidekiq/client.rb +76 -53
- data/lib/sidekiq/delay.rb +41 -0
- data/lib/sidekiq/exception_handler.rb +12 -16
- 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 +12 -4
- 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 +259 -0
- data/lib/sidekiq/launcher.rb +170 -71
- data/lib/sidekiq/logger.rb +166 -0
- data/lib/sidekiq/manager.rb +17 -20
- data/lib/sidekiq/middleware/chain.rb +20 -8
- data/lib/sidekiq/middleware/current_attributes.rb +52 -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 +169 -78
- data/lib/sidekiq/rails.rb +41 -36
- data/lib/sidekiq/redis_connection.rb +65 -20
- data/lib/sidekiq/scheduled.rb +85 -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 +48 -15
- data/lib/sidekiq/version.rb +2 -1
- data/lib/sidekiq/web/action.rb +15 -17
- data/lib/sidekiq/web/application.rb +114 -92
- 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 +85 -76
- data/lib/sidekiq/worker.rb +233 -43
- data/lib/sidekiq.rb +88 -64
- data/sidekiq.gemspec +24 -22
- data/web/assets/images/apple-touch-icon.png +0 -0
- data/web/assets/javascripts/application.js +86 -59
- data/web/assets/javascripts/dashboard.js +81 -85
- data/web/assets/stylesheets/application-dark.css +147 -0
- data/web/assets/stylesheets/application-rtl.css +242 -0
- data/web/assets/stylesheets/application.css +319 -141
- 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 +44 -194
- 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 -570
- data/Rakefile +0 -9
- data/bin/sidekiqctl +0 -99
- data/code_of_conduct.md +0 -50
- 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 -201
- 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 -50
- 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 -666
- 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,44 +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
|
-
Sidekiq.options[:reloader] = Sidekiq::Rails::Reloader.new
|
|
244
274
|
end
|
|
245
275
|
options[:tag] ||= default_tag
|
|
246
276
|
else
|
|
247
|
-
|
|
248
|
-
"./#{options[:require]} or /path/to/#{options[:require]}"
|
|
249
|
-
|
|
250
|
-
require(options[:require]) || raise(ArgumentError, not_required_message)
|
|
277
|
+
require options[:require]
|
|
251
278
|
end
|
|
252
279
|
end
|
|
253
280
|
|
|
254
281
|
def default_tag
|
|
255
282
|
dir = ::Rails.root
|
|
256
283
|
name = File.basename(dir)
|
|
257
|
-
|
|
258
|
-
|
|
284
|
+
prevdir = File.dirname(dir) # Capistrano release directory?
|
|
285
|
+
if name.to_i != 0 && prevdir
|
|
286
|
+
if File.basename(prevdir) == "releases"
|
|
259
287
|
return File.basename(File.dirname(prevdir))
|
|
260
288
|
end
|
|
261
289
|
end
|
|
@@ -263,12 +291,10 @@ module Sidekiq
|
|
|
263
291
|
end
|
|
264
292
|
|
|
265
293
|
def validate!
|
|
266
|
-
options[:queues] << 'default' if options[:queues].empty?
|
|
267
|
-
|
|
268
294
|
if !File.exist?(options[:require]) ||
|
|
269
|
-
|
|
295
|
+
(File.directory?(options[:require]) && !File.exist?("#{options[:require]}/config/application.rb"))
|
|
270
296
|
logger.info "=================================================================="
|
|
271
|
-
logger.info " Please point
|
|
297
|
+
logger.info " Please point Sidekiq to a Rails application or a Ruby file "
|
|
272
298
|
logger.info " to load your worker classes with -r [DIR|FILE]."
|
|
273
299
|
logger.info "=================================================================="
|
|
274
300
|
logger.info @parser
|
|
@@ -276,44 +302,45 @@ module Sidekiq
|
|
|
276
302
|
end
|
|
277
303
|
|
|
278
304
|
[:concurrency, :timeout].each do |opt|
|
|
279
|
-
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
|
|
280
306
|
end
|
|
281
307
|
end
|
|
282
308
|
|
|
283
309
|
def parse_options(argv)
|
|
284
310
|
opts = {}
|
|
311
|
+
@parser = option_parser(opts)
|
|
312
|
+
@parser.parse!(argv)
|
|
313
|
+
opts
|
|
314
|
+
end
|
|
285
315
|
|
|
286
|
-
|
|
287
|
-
|
|
316
|
+
def option_parser(opts)
|
|
317
|
+
parser = OptionParser.new { |o|
|
|
318
|
+
o.on "-c", "--concurrency INT", "processor threads to use" do |arg|
|
|
288
319
|
opts[:concurrency] = Integer(arg)
|
|
289
320
|
end
|
|
290
321
|
|
|
291
|
-
o.on
|
|
292
|
-
|
|
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"
|
|
293
324
|
end
|
|
294
325
|
|
|
295
|
-
o.on
|
|
326
|
+
o.on "-e", "--environment ENV", "Application environment" do |arg|
|
|
296
327
|
opts[:environment] = arg
|
|
297
328
|
end
|
|
298
329
|
|
|
299
|
-
o.on
|
|
330
|
+
o.on "-g", "--tag TAG", "Process tag for procline" do |arg|
|
|
300
331
|
opts[:tag] = arg
|
|
301
332
|
end
|
|
302
333
|
|
|
303
|
-
o.on '-i', '--index INT', "unique process index on this machine" do |arg|
|
|
304
|
-
opts[:index] = Integer(arg.match(/\d+/)[0])
|
|
305
|
-
end
|
|
306
|
-
|
|
307
334
|
o.on "-q", "--queue QUEUE[,WEIGHT]", "Queues to process with optional weights" do |arg|
|
|
308
335
|
queue, weight = arg.split(",")
|
|
309
336
|
parse_queue opts, queue, weight
|
|
310
337
|
end
|
|
311
338
|
|
|
312
|
-
o.on
|
|
339
|
+
o.on "-r", "--require [PATH|DIR]", "Location of Rails application with workers or file to require" do |arg|
|
|
313
340
|
opts[:require] = arg
|
|
314
341
|
end
|
|
315
342
|
|
|
316
|
-
o.on
|
|
343
|
+
o.on "-t", "--timeout NUM", "Shutdown timeout" do |arg|
|
|
317
344
|
opts[:timeout] = Integer(arg)
|
|
318
345
|
end
|
|
319
346
|
|
|
@@ -321,69 +348,51 @@ module Sidekiq
|
|
|
321
348
|
opts[:verbose] = arg
|
|
322
349
|
end
|
|
323
350
|
|
|
324
|
-
o.on
|
|
351
|
+
o.on "-C", "--config PATH", "path to YAML config file" do |arg|
|
|
325
352
|
opts[:config_file] = arg
|
|
326
353
|
end
|
|
327
354
|
|
|
328
|
-
o.on
|
|
329
|
-
|
|
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"
|
|
330
357
|
end
|
|
331
358
|
|
|
332
|
-
o.on
|
|
333
|
-
|
|
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"
|
|
334
361
|
end
|
|
335
362
|
|
|
336
|
-
o.on
|
|
363
|
+
o.on "-V", "--version", "Print version and exit" do |arg|
|
|
337
364
|
puts "Sidekiq #{Sidekiq::VERSION}"
|
|
338
365
|
die(0)
|
|
339
366
|
end
|
|
340
|
-
|
|
367
|
+
}
|
|
341
368
|
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
logger.info
|
|
369
|
+
parser.banner = "sidekiq [options]"
|
|
370
|
+
parser.on_tail "-h", "--help", "Show help" do
|
|
371
|
+
logger.info parser
|
|
345
372
|
die 1
|
|
346
373
|
end
|
|
347
|
-
@parser.parse!(argv)
|
|
348
374
|
|
|
349
|
-
|
|
350
|
-
opts[:config_file] ||= filename if File.exist?(filename)
|
|
351
|
-
end
|
|
352
|
-
|
|
353
|
-
opts
|
|
375
|
+
parser
|
|
354
376
|
end
|
|
355
377
|
|
|
356
378
|
def initialize_logger
|
|
357
|
-
Sidekiq::Logging.initialize_logger(options[:logfile]) if options[:logfile]
|
|
358
|
-
|
|
359
379
|
Sidekiq.logger.level = ::Logger::DEBUG if options[:verbose]
|
|
360
380
|
end
|
|
361
381
|
|
|
362
|
-
def
|
|
363
|
-
|
|
364
|
-
pidfile = File.expand_path(path)
|
|
365
|
-
File.open(pidfile, 'w') do |f|
|
|
366
|
-
f.puts ::Process.pid
|
|
367
|
-
end
|
|
368
|
-
end
|
|
369
|
-
end
|
|
382
|
+
def parse_config(path)
|
|
383
|
+
opts = YAML.load(ERB.new(File.read(path)).result) || {}
|
|
370
384
|
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
if File.exist?(cfile)
|
|
374
|
-
opts = YAML.load(ERB.new(IO.read(cfile)).result) || opts
|
|
375
|
-
opts = opts.merge(opts.delete(environment) || {})
|
|
376
|
-
parse_queues(opts, opts.delete(:queues) || [])
|
|
385
|
+
if opts.respond_to? :deep_symbolize_keys!
|
|
386
|
+
opts.deep_symbolize_keys!
|
|
377
387
|
else
|
|
378
|
-
|
|
379
|
-
# can be deployed by cap with just the defaults.
|
|
380
|
-
end
|
|
381
|
-
ns = opts.delete(:namespace)
|
|
382
|
-
if ns
|
|
383
|
-
# logger hasn't been initialized yet, puts is all we have.
|
|
384
|
-
puts("namespace should be set in your ruby initializer, is ignored in config file")
|
|
385
|
-
puts("config.redis = { :url => ..., :namespace => '#{ns}' }")
|
|
388
|
+
symbolize_keys_deep!(opts)
|
|
386
389
|
end
|
|
390
|
+
|
|
391
|
+
opts = opts.merge(opts.delete(environment.to_sym) || {})
|
|
392
|
+
opts.delete(:strict)
|
|
393
|
+
|
|
394
|
+
parse_queues(opts, opts.delete(:queues) || [])
|
|
395
|
+
|
|
387
396
|
opts
|
|
388
397
|
end
|
|
389
398
|
|
|
@@ -391,11 +400,18 @@ module Sidekiq
|
|
|
391
400
|
queues_and_weights.each { |queue_and_weight| parse_queue(opts, *queue_and_weight) }
|
|
392
401
|
end
|
|
393
402
|
|
|
394
|
-
def parse_queue(opts,
|
|
395
|
-
[
|
|
396
|
-
|
|
397
|
-
|
|
403
|
+
def parse_queue(opts, queue, weight = nil)
|
|
404
|
+
opts[:queues] ||= []
|
|
405
|
+
opts[:strict] = true if opts[:strict].nil?
|
|
406
|
+
raise ArgumentError, "queues: #{queue} cannot be defined twice" if opts[:queues].include?(queue)
|
|
407
|
+
[weight.to_i, 1].max.times { opts[:queues] << queue.to_s }
|
|
398
408
|
opts[:strict] = false if weight.to_i > 0
|
|
399
409
|
end
|
|
410
|
+
|
|
411
|
+
def rails_app?
|
|
412
|
+
defined?(::Rails) && ::Rails.respond_to?(:application)
|
|
413
|
+
end
|
|
400
414
|
end
|
|
401
415
|
end
|
|
416
|
+
|
|
417
|
+
require "sidekiq/systemd"
|