sidekiq 4.2.10 → 6.1.2

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