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