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.

Files changed (106) hide show
  1. checksums.yaml +5 -5
  2. data/Changes.md +391 -1
  3. data/LICENSE +3 -3
  4. data/README.md +23 -34
  5. data/bin/sidekiq +27 -3
  6. data/bin/sidekiqload +68 -62
  7. data/bin/sidekiqmon +8 -0
  8. data/lib/generators/sidekiq/job_generator.rb +57 -0
  9. data/lib/generators/sidekiq/templates/{worker.rb.erb → job.rb.erb} +2 -2
  10. data/lib/generators/sidekiq/templates/{worker_spec.rb.erb → job_spec.rb.erb} +1 -1
  11. data/lib/generators/sidekiq/templates/{worker_test.rb.erb → job_test.rb.erb} +1 -1
  12. data/lib/sidekiq/api.rb +344 -243
  13. data/lib/sidekiq/cli.rb +209 -221
  14. data/lib/sidekiq/client.rb +62 -64
  15. data/lib/sidekiq/delay.rb +7 -6
  16. data/lib/sidekiq/exception_handler.rb +10 -12
  17. data/lib/sidekiq/extensions/action_mailer.rb +13 -22
  18. data/lib/sidekiq/extensions/active_record.rb +13 -10
  19. data/lib/sidekiq/extensions/class_methods.rb +14 -11
  20. data/lib/sidekiq/extensions/generic_proxy.rb +6 -4
  21. data/lib/sidekiq/fetch.rb +40 -32
  22. data/lib/sidekiq/job.rb +13 -0
  23. data/lib/sidekiq/job_logger.rb +35 -9
  24. data/lib/sidekiq/job_retry.rb +88 -68
  25. data/lib/sidekiq/job_util.rb +65 -0
  26. data/lib/sidekiq/launcher.rb +170 -73
  27. data/lib/sidekiq/logger.rb +170 -0
  28. data/lib/sidekiq/manager.rb +18 -22
  29. data/lib/sidekiq/middleware/chain.rb +20 -8
  30. data/lib/sidekiq/middleware/current_attributes.rb +57 -0
  31. data/lib/sidekiq/middleware/i18n.rb +5 -7
  32. data/lib/sidekiq/monitor.rb +133 -0
  33. data/lib/sidekiq/paginator.rb +20 -16
  34. data/lib/sidekiq/processor.rb +135 -83
  35. data/lib/sidekiq/rails.rb +42 -38
  36. data/lib/sidekiq/redis_connection.rb +49 -30
  37. data/lib/sidekiq/scheduled.rb +94 -31
  38. data/lib/sidekiq/sd_notify.rb +149 -0
  39. data/lib/sidekiq/systemd.rb +24 -0
  40. data/lib/sidekiq/testing/inline.rb +2 -1
  41. data/lib/sidekiq/testing.rb +40 -31
  42. data/lib/sidekiq/util.rb +57 -15
  43. data/lib/sidekiq/version.rb +2 -1
  44. data/lib/sidekiq/web/action.rb +15 -11
  45. data/lib/sidekiq/web/application.rb +109 -74
  46. data/lib/sidekiq/web/csrf_protection.rb +180 -0
  47. data/lib/sidekiq/web/helpers.rb +117 -93
  48. data/lib/sidekiq/web/router.rb +23 -19
  49. data/lib/sidekiq/web.rb +61 -105
  50. data/lib/sidekiq/worker.rb +257 -99
  51. data/lib/sidekiq.rb +81 -46
  52. data/sidekiq.gemspec +23 -23
  53. data/web/assets/images/apple-touch-icon.png +0 -0
  54. data/web/assets/javascripts/application.js +83 -64
  55. data/web/assets/javascripts/dashboard.js +66 -75
  56. data/web/assets/stylesheets/application-dark.css +143 -0
  57. data/web/assets/stylesheets/application-rtl.css +0 -4
  58. data/web/assets/stylesheets/application.css +77 -231
  59. data/web/assets/stylesheets/bootstrap.css +2 -2
  60. data/web/locales/ar.yml +9 -2
  61. data/web/locales/de.yml +14 -2
  62. data/web/locales/en.yml +7 -1
  63. data/web/locales/es.yml +21 -5
  64. data/web/locales/fr.yml +10 -3
  65. data/web/locales/ja.yml +7 -1
  66. data/web/locales/lt.yml +83 -0
  67. data/web/locales/pl.yml +4 -4
  68. data/web/locales/ru.yml +4 -0
  69. data/web/locales/vi.yml +83 -0
  70. data/web/views/_footer.erb +1 -1
  71. data/web/views/_job_info.erb +3 -2
  72. data/web/views/_nav.erb +3 -17
  73. data/web/views/_poll_link.erb +2 -5
  74. data/web/views/_summary.erb +7 -7
  75. data/web/views/busy.erb +54 -20
  76. data/web/views/dashboard.erb +22 -14
  77. data/web/views/dead.erb +3 -3
  78. data/web/views/layout.erb +4 -2
  79. data/web/views/morgue.erb +9 -6
  80. data/web/views/queue.erb +20 -10
  81. data/web/views/queues.erb +11 -3
  82. data/web/views/retries.erb +14 -7
  83. data/web/views/retry.erb +3 -3
  84. data/web/views/scheduled.erb +5 -2
  85. metadata +39 -136
  86. data/.github/contributing.md +0 -32
  87. data/.github/issue_template.md +0 -11
  88. data/.gitignore +0 -13
  89. data/.travis.yml +0 -14
  90. data/3.0-Upgrade.md +0 -70
  91. data/4.0-Upgrade.md +0 -53
  92. data/5.0-Upgrade.md +0 -56
  93. data/COMM-LICENSE +0 -95
  94. data/Ent-Changes.md +0 -216
  95. data/Gemfile +0 -8
  96. data/Pro-2.0-Upgrade.md +0 -138
  97. data/Pro-3.0-Upgrade.md +0 -44
  98. data/Pro-4.0-Upgrade.md +0 -35
  99. data/Pro-Changes.md +0 -729
  100. data/Rakefile +0 -8
  101. data/bin/sidekiqctl +0 -99
  102. data/code_of_conduct.md +0 -50
  103. data/lib/generators/sidekiq/worker_generator.rb +0 -49
  104. data/lib/sidekiq/core_ext.rb +0 -1
  105. data/lib/sidekiq/logging.rb +0 -122
  106. 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 'yaml'
5
- require 'singleton'
6
- require 'optparse'
7
- require 'erb'
8
- require 'fileutils'
5
+ require "yaml"
6
+ require "singleton"
7
+ require "optparse"
8
+ require "erb"
9
+ require "fileutils"
9
10
 
10
- require 'sidekiq'
11
- require 'sidekiq/util'
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 initialize
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
- boot_system
54
- print_banner
36
+ def run(boot_app: true)
37
+ boot_application if boot_app
55
38
 
56
- self_read, self_write = IO.pipe
57
- sigs = %w(INT TERM TTIN TSTP)
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
- begin
66
- trap sig do
67
- self_write.write("#{sig}\n")
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
- rescue ArgumentError
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: http://sidekiq.org" unless defined?(::Sidekiq::Pro)
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
- ver = Sidekiq.redis_info['redis_version']
81
- raise "You are using Redis v#{ver}, Sidekiq requires Redis v2.8.0 or greater" if ver < '2.8'
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
- if !options[:daemon]
97
- logger.info 'Starting processing, hit Ctrl-C to stop'
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 = IO.select([self_read])
107
- signal = readable_io.first[0].gets.strip
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 'Shutting down'
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
- %q{
122
- m,
123
- `$b
124
- .ss, $$: .,d$
125
- `$$P,d$P' .,md$P"'
126
- ,$$$$$bmmd$$$P^'
127
- .d$$$$$$$$$$P'
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
- 'INT' => ->(cli) { raise Interrupt },
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
- 'TERM' => ->(cli) { raise Interrupt },
143
- 'USR1' => ->(cli) {
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
- 'USR2' => ->(cli) {
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['sidekiq_label']}"
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
- handy = SIGNAL_HANDLERS[sig]
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
- # Print logo and banner for development
183
- if environment == 'development' && $stdout.tty?
184
- puts "\e[#{31}m"
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
- @environment = cli_env || ENV['RAILS_ENV'] || ENV['RACK_ENV'] || 'development'
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].kind_of? Hash
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
- cfile = opts[:config_file]
240
- opts = parse_config(cfile).merge(opts) if cfile
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
- opts[:strict] = true if opts[:strict].nil?
243
- opts[:concurrency] = Integer(ENV["RAILS_MAX_THREADS"]) if !opts[:concurrency] && ENV["RAILS_MAX_THREADS"]
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 boot_system
253
- ENV['RACK_ENV'] = ENV['RAILS_ENV'] = environment
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 'rails'
259
- if ::Rails::VERSION::MAJOR < 4
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 'sidekiq/rails'
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
- not_required_message = "#{options[:require]} was not required, you should use an explicit path: " +
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
- if name.to_i != 0 && prevdir = File.dirname(dir) # Capistrano release directory?
287
- if File.basename(prevdir) == 'releases'
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
- (File.directory?(options[:require]) && !File.exist?("#{options[:require]}/config/application.rb"))
295
+ (File.directory?(options[:require]) && !File.exist?("#{options[:require]}/config/application.rb"))
299
296
  logger.info "=================================================================="
300
- logger.info " Please point sidekiq to a Rails 4/5 application or a Ruby file "
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.has_key?(opt) && options[opt].to_i <= 0
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
- @parser = OptionParser.new do |o|
316
- o.on '-c', '--concurrency INT', "processor threads to use" do |arg|
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 '-d', '--daemon', "Daemonize process" do |arg|
321
- opts[:daemon] = arg
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 '-e', '--environment ENV', "Application environment" do |arg|
326
+ o.on "-e", "--environment ENV", "Application environment" do |arg|
325
327
  opts[:environment] = arg
326
328
  end
327
329
 
328
- o.on '-g', '--tag TAG', "Process tag for procline" do |arg|
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 '-r', '--require [PATH|DIR]', "Location of Rails application with workers or file to require" do |arg|
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 '-t', '--timeout NUM', "Shutdown timeout" do |arg|
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 '-C', '--config PATH', "path to YAML config file" do |arg|
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 '-L', '--logfile PATH', "path to writable logfile" do |arg|
360
- opts[:logfile] = arg
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 '-P', '--pidfile PATH', "path to pidfile" do |arg|
364
- opts[:pidfile] = arg
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 '-V', '--version', "Print version and exit" do |arg|
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
- end
367
+ }
372
368
 
373
- @parser.banner = "sidekiq [options]"
374
- @parser.on_tail "-h", "--help", "Show help" do
375
- logger.info @parser
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
- opts
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 write_pid
394
- if path = options[:pidfile]
395
- pidfile = File.expand_path(path)
396
- File.open(pidfile, 'w') do |f|
397
- f.puts ::Process.pid
398
- end
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
- def parse_config(cfile)
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
- if opts.respond_to? :deep_symbolize_keys!
408
- opts.deep_symbolize_keys!
409
- else
410
- symbolize_keys_deep!(opts)
411
- end
396
+ parse_queues(opts, opts.delete(:queues) || [])
397
+
398
+ opts
399
+ end
412
400
 
413
- opts = opts.merge(opts.delete(environment.to_sym) || {})
414
- parse_queues(opts, opts.delete(:queues) || [])
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
- # allow a non-existent config file so Sidekiq
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, q, weight=nil)
433
- [weight.to_i, 1].max.times do
434
- (opts[:queues] ||= []) << q
435
- end
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"