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.
Files changed (134) hide show
  1. checksums.yaml +5 -5
  2. data/Changes.md +445 -0
  3. data/LICENSE +1 -1
  4. data/README.md +21 -34
  5. data/bin/sidekiq +26 -2
  6. data/bin/sidekiqload +28 -38
  7. data/bin/sidekiqmon +8 -0
  8. data/lib/generators/sidekiq/templates/worker_spec.rb.erb +1 -1
  9. data/lib/generators/sidekiq/templates/worker_test.rb.erb +2 -2
  10. data/lib/generators/sidekiq/worker_generator.rb +21 -13
  11. data/lib/sidekiq/api.rb +347 -213
  12. data/lib/sidekiq/cli.rb +221 -212
  13. data/lib/sidekiq/client.rb +75 -52
  14. data/lib/sidekiq/delay.rb +41 -0
  15. data/lib/sidekiq/exception_handler.rb +12 -16
  16. data/lib/sidekiq/extensions/action_mailer.rb +13 -22
  17. data/lib/sidekiq/extensions/active_record.rb +13 -10
  18. data/lib/sidekiq/extensions/class_methods.rb +14 -11
  19. data/lib/sidekiq/extensions/generic_proxy.rb +10 -4
  20. data/lib/sidekiq/fetch.rb +38 -31
  21. data/lib/sidekiq/job_logger.rb +63 -0
  22. data/lib/sidekiq/job_retry.rb +263 -0
  23. data/lib/sidekiq/launcher.rb +169 -70
  24. data/lib/sidekiq/logger.rb +166 -0
  25. data/lib/sidekiq/manager.rb +17 -20
  26. data/lib/sidekiq/middleware/chain.rb +15 -5
  27. data/lib/sidekiq/middleware/i18n.rb +5 -7
  28. data/lib/sidekiq/monitor.rb +133 -0
  29. data/lib/sidekiq/paginator.rb +18 -14
  30. data/lib/sidekiq/processor.rb +161 -70
  31. data/lib/sidekiq/rails.rb +30 -73
  32. data/lib/sidekiq/redis_connection.rb +67 -20
  33. data/lib/sidekiq/scheduled.rb +61 -35
  34. data/lib/sidekiq/sd_notify.rb +149 -0
  35. data/lib/sidekiq/systemd.rb +24 -0
  36. data/lib/sidekiq/testing/inline.rb +2 -1
  37. data/lib/sidekiq/testing.rb +54 -26
  38. data/lib/sidekiq/util.rb +48 -15
  39. data/lib/sidekiq/version.rb +2 -1
  40. data/lib/sidekiq/web/action.rb +15 -15
  41. data/lib/sidekiq/web/application.rb +112 -89
  42. data/lib/sidekiq/web/csrf_protection.rb +180 -0
  43. data/lib/sidekiq/web/helpers.rb +153 -73
  44. data/lib/sidekiq/web/router.rb +27 -19
  45. data/lib/sidekiq/web.rb +64 -109
  46. data/lib/sidekiq/worker.rb +164 -41
  47. data/lib/sidekiq.rb +86 -60
  48. data/sidekiq.gemspec +24 -22
  49. data/web/assets/images/apple-touch-icon.png +0 -0
  50. data/web/assets/javascripts/application.js +25 -27
  51. data/web/assets/javascripts/dashboard.js +34 -38
  52. data/web/assets/stylesheets/application-dark.css +160 -0
  53. data/web/assets/stylesheets/application-rtl.css +246 -0
  54. data/web/assets/stylesheets/application.css +402 -12
  55. data/web/assets/stylesheets/bootstrap-rtl.min.css +9 -0
  56. data/web/assets/stylesheets/bootstrap.css +2 -2
  57. data/web/locales/ar.yml +81 -0
  58. data/web/locales/de.yml +14 -2
  59. data/web/locales/en.yml +4 -0
  60. data/web/locales/es.yml +4 -3
  61. data/web/locales/fa.yml +80 -0
  62. data/web/locales/fr.yml +3 -3
  63. data/web/locales/he.yml +79 -0
  64. data/web/locales/ja.yml +9 -4
  65. data/web/locales/lt.yml +83 -0
  66. data/web/locales/pl.yml +4 -4
  67. data/web/locales/ru.yml +4 -0
  68. data/web/locales/ur.yml +80 -0
  69. data/web/locales/vi.yml +83 -0
  70. data/web/views/_footer.erb +5 -2
  71. data/web/views/_job_info.erb +3 -2
  72. data/web/views/_nav.erb +4 -18
  73. data/web/views/_paging.erb +1 -1
  74. data/web/views/busy.erb +57 -19
  75. data/web/views/dashboard.erb +3 -3
  76. data/web/views/dead.erb +2 -2
  77. data/web/views/layout.erb +13 -2
  78. data/web/views/morgue.erb +19 -12
  79. data/web/views/queue.erb +22 -12
  80. data/web/views/queues.erb +13 -3
  81. data/web/views/retries.erb +22 -13
  82. data/web/views/retry.erb +3 -3
  83. data/web/views/scheduled.erb +7 -4
  84. metadata +42 -194
  85. data/.github/contributing.md +0 -32
  86. data/.github/issue_template.md +0 -4
  87. data/.gitignore +0 -12
  88. data/.travis.yml +0 -12
  89. data/3.0-Upgrade.md +0 -70
  90. data/4.0-Upgrade.md +0 -53
  91. data/COMM-LICENSE +0 -95
  92. data/Ent-Changes.md +0 -146
  93. data/Gemfile +0 -29
  94. data/Pro-2.0-Upgrade.md +0 -138
  95. data/Pro-3.0-Upgrade.md +0 -44
  96. data/Pro-Changes.md +0 -585
  97. data/Rakefile +0 -9
  98. data/bin/sidekiqctl +0 -99
  99. data/code_of_conduct.md +0 -50
  100. data/lib/sidekiq/core_ext.rb +0 -106
  101. data/lib/sidekiq/logging.rb +0 -106
  102. data/lib/sidekiq/middleware/server/active_record.rb +0 -13
  103. data/lib/sidekiq/middleware/server/logging.rb +0 -40
  104. data/lib/sidekiq/middleware/server/retry_jobs.rb +0 -205
  105. data/test/config.yml +0 -9
  106. data/test/env_based_config.yml +0 -11
  107. data/test/fake_env.rb +0 -1
  108. data/test/fixtures/en.yml +0 -2
  109. data/test/helper.rb +0 -75
  110. data/test/test_actors.rb +0 -138
  111. data/test/test_api.rb +0 -528
  112. data/test/test_cli.rb +0 -418
  113. data/test/test_client.rb +0 -266
  114. data/test/test_exception_handler.rb +0 -56
  115. data/test/test_extensions.rb +0 -127
  116. data/test/test_fetch.rb +0 -50
  117. data/test/test_launcher.rb +0 -95
  118. data/test/test_logging.rb +0 -35
  119. data/test/test_manager.rb +0 -50
  120. data/test/test_middleware.rb +0 -158
  121. data/test/test_processor.rb +0 -235
  122. data/test/test_rails.rb +0 -22
  123. data/test/test_redis_connection.rb +0 -132
  124. data/test/test_retry.rb +0 -326
  125. data/test/test_retry_exhausted.rb +0 -149
  126. data/test/test_scheduled.rb +0 -115
  127. data/test/test_scheduling.rb +0 -58
  128. data/test/test_sidekiq.rb +0 -107
  129. data/test/test_testing.rb +0 -143
  130. data/test/test_testing_fake.rb +0 -357
  131. data/test/test_testing_inline.rb +0 -94
  132. data/test/test_util.rb +0 -13
  133. data/test/test_web.rb +0 -726
  134. 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
- # encoding: utf-8
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).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
+ 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
- if !options[:daemon]
85
- logger.info 'Starting processing, hit Ctrl-C to stop'
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 'Shutting down'
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
- %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
- }
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
- 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 '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['label']}"
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
- end
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
- # Print logo and banner for development
159
- if environment == 'development' && $stdout.tty?
160
- puts "\e[#{31}m"
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 daemonize
167
- return unless options[:daemon]
168
-
169
- raise ArgumentError, "You really should set a logfile if you're going to daemonize" unless options[:logfile]
170
- files_to_reopen = []
171
- ObjectSpace.each_object(File) do |file|
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 set_environment(cli_env)
197
- @environment = cli_env || ENV['RAILS_ENV'] || ENV['RACK_ENV'] || 'development'
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
- cfile = opts[:config_file]
208
- opts = parse_config(cfile).merge(opts) if cfile
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
- opts[:strict] = true if opts[:strict].nil?
211
- opts[:concurrency] = Integer(ENV["RAILS_MAX_THREADS"]) if !opts[:concurrency] && ENV["RAILS_MAX_THREADS"]
212
- opts[:identity] = identity
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 boot_system
222
- ENV['RACK_ENV'] = ENV['RAILS_ENV'] = environment
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 'rails'
228
- if ::Rails::VERSION::MAJOR < 4
229
- require 'sidekiq/rails'
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 'sidekiq/rails'
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
- not_required_message = "#{options[:require]} was not required, you should use an explicit path: " +
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
- if name.to_i != 0 && prevdir = File.dirname(dir) # Capistrano release directory?
257
- if File.basename(prevdir) == 'releases'
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
- (File.directory?(options[:require]) && !File.exist?("#{options[:require]}/config/application.rb"))
287
+ (File.directory?(options[:require]) && !File.exist?("#{options[:require]}/config/application.rb"))
269
288
  logger.info "=================================================================="
270
- logger.info " Please point sidekiq to a Rails 3/4 application or a Ruby file "
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.has_key?(opt) && options[opt].to_i <= 0
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
- @parser = OptionParser.new do |o|
286
- o.on '-c', '--concurrency INT', "processor threads to use" do |arg|
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 '-d', '--daemon', "Daemonize process" do |arg|
291
- opts[:daemon] = arg
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 '-e', '--environment ENV', "Application environment" do |arg|
318
+ o.on "-e", "--environment ENV", "Application environment" do |arg|
295
319
  opts[:environment] = arg
296
320
  end
297
321
 
298
- o.on '-g', '--tag TAG', "Process tag for procline" do |arg|
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 '-r', '--require [PATH|DIR]', "Location of Rails application with workers or file to require" do |arg|
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 '-t', '--timeout NUM', "Shutdown timeout" do |arg|
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 '-C', '--config PATH', "path to YAML config file" do |arg|
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 '-L', '--logfile PATH', "path to writable logfile" do |arg|
328
- opts[:logfile] = arg
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 '-P', '--pidfile PATH', "path to pidfile" do |arg|
332
- opts[:pidfile] = arg
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 '-V', '--version', "Print version and exit" do |arg|
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
- end
359
+ }
340
360
 
341
- @parser.banner = "sidekiq [options]"
342
- @parser.on_tail "-h", "--help", "Show help" do
343
- logger.info @parser
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
- opts
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 write_pid
362
- if path = options[:pidfile]
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
- def parse_config(cfile)
371
- opts = {}
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
- # allow a non-existent config file so Sidekiq
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, q, weight=nil)
394
- [weight.to_i, 1].max.times do
395
- (opts[:queues] ||= []) << q
396
- end
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"