sidekiq 5.2.10 → 6.5.6

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