sidekiq 4.2.2 → 6.3.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 (138) hide show
  1. checksums.yaml +5 -5
  2. data/Changes.md +516 -0
  3. data/LICENSE +2 -2
  4. data/README.md +23 -36
  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 +401 -243
  12. data/lib/sidekiq/cli.rb +228 -212
  13. data/lib/sidekiq/client.rb +76 -53
  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 +12 -4
  20. data/lib/sidekiq/fetch.rb +39 -31
  21. data/lib/sidekiq/job.rb +13 -0
  22. data/lib/sidekiq/job_logger.rb +63 -0
  23. data/lib/sidekiq/job_retry.rb +259 -0
  24. data/lib/sidekiq/launcher.rb +170 -71
  25. data/lib/sidekiq/logger.rb +166 -0
  26. data/lib/sidekiq/manager.rb +17 -20
  27. data/lib/sidekiq/middleware/chain.rb +20 -8
  28. data/lib/sidekiq/middleware/current_attributes.rb +52 -0
  29. data/lib/sidekiq/middleware/i18n.rb +5 -7
  30. data/lib/sidekiq/monitor.rb +133 -0
  31. data/lib/sidekiq/paginator.rb +18 -14
  32. data/lib/sidekiq/processor.rb +169 -78
  33. data/lib/sidekiq/rails.rb +41 -36
  34. data/lib/sidekiq/redis_connection.rb +65 -20
  35. data/lib/sidekiq/scheduled.rb +85 -34
  36. data/lib/sidekiq/sd_notify.rb +149 -0
  37. data/lib/sidekiq/systemd.rb +24 -0
  38. data/lib/sidekiq/testing/inline.rb +2 -1
  39. data/lib/sidekiq/testing.rb +52 -26
  40. data/lib/sidekiq/util.rb +48 -15
  41. data/lib/sidekiq/version.rb +2 -1
  42. data/lib/sidekiq/web/action.rb +15 -17
  43. data/lib/sidekiq/web/application.rb +114 -92
  44. data/lib/sidekiq/web/csrf_protection.rb +180 -0
  45. data/lib/sidekiq/web/helpers.rb +151 -83
  46. data/lib/sidekiq/web/router.rb +27 -19
  47. data/lib/sidekiq/web.rb +85 -76
  48. data/lib/sidekiq/worker.rb +233 -43
  49. data/lib/sidekiq.rb +88 -64
  50. data/sidekiq.gemspec +24 -22
  51. data/web/assets/images/apple-touch-icon.png +0 -0
  52. data/web/assets/javascripts/application.js +86 -59
  53. data/web/assets/javascripts/dashboard.js +81 -85
  54. data/web/assets/stylesheets/application-dark.css +147 -0
  55. data/web/assets/stylesheets/application-rtl.css +242 -0
  56. data/web/assets/stylesheets/application.css +319 -141
  57. data/web/assets/stylesheets/bootstrap-rtl.min.css +9 -0
  58. data/web/assets/stylesheets/bootstrap.css +2 -2
  59. data/web/locales/ar.yml +87 -0
  60. data/web/locales/de.yml +14 -2
  61. data/web/locales/en.yml +8 -1
  62. data/web/locales/es.yml +22 -5
  63. data/web/locales/fa.yml +80 -0
  64. data/web/locales/fr.yml +10 -3
  65. data/web/locales/he.yml +79 -0
  66. data/web/locales/ja.yml +12 -4
  67. data/web/locales/lt.yml +83 -0
  68. data/web/locales/pl.yml +4 -4
  69. data/web/locales/ru.yml +4 -0
  70. data/web/locales/ur.yml +80 -0
  71. data/web/locales/vi.yml +83 -0
  72. data/web/views/_footer.erb +5 -2
  73. data/web/views/_job_info.erb +4 -3
  74. data/web/views/_nav.erb +4 -18
  75. data/web/views/_paging.erb +1 -1
  76. data/web/views/_poll_link.erb +2 -5
  77. data/web/views/_summary.erb +7 -7
  78. data/web/views/busy.erb +60 -22
  79. data/web/views/dashboard.erb +23 -15
  80. data/web/views/dead.erb +3 -3
  81. data/web/views/layout.erb +14 -3
  82. data/web/views/morgue.erb +19 -12
  83. data/web/views/queue.erb +24 -14
  84. data/web/views/queues.erb +14 -4
  85. data/web/views/retries.erb +22 -13
  86. data/web/views/retry.erb +4 -4
  87. data/web/views/scheduled.erb +7 -4
  88. metadata +44 -194
  89. data/.github/contributing.md +0 -32
  90. data/.github/issue_template.md +0 -4
  91. data/.gitignore +0 -12
  92. data/.travis.yml +0 -12
  93. data/3.0-Upgrade.md +0 -70
  94. data/4.0-Upgrade.md +0 -53
  95. data/COMM-LICENSE +0 -95
  96. data/Ent-Changes.md +0 -146
  97. data/Gemfile +0 -29
  98. data/Pro-2.0-Upgrade.md +0 -138
  99. data/Pro-3.0-Upgrade.md +0 -44
  100. data/Pro-Changes.md +0 -570
  101. data/Rakefile +0 -9
  102. data/bin/sidekiqctl +0 -99
  103. data/code_of_conduct.md +0 -50
  104. data/lib/sidekiq/core_ext.rb +0 -106
  105. data/lib/sidekiq/logging.rb +0 -106
  106. data/lib/sidekiq/middleware/server/active_record.rb +0 -13
  107. data/lib/sidekiq/middleware/server/logging.rb +0 -40
  108. data/lib/sidekiq/middleware/server/retry_jobs.rb +0 -205
  109. data/test/config.yml +0 -9
  110. data/test/env_based_config.yml +0 -11
  111. data/test/fake_env.rb +0 -1
  112. data/test/fixtures/en.yml +0 -2
  113. data/test/helper.rb +0 -75
  114. data/test/test_actors.rb +0 -138
  115. data/test/test_api.rb +0 -528
  116. data/test/test_cli.rb +0 -418
  117. data/test/test_client.rb +0 -266
  118. data/test/test_exception_handler.rb +0 -56
  119. data/test/test_extensions.rb +0 -127
  120. data/test/test_fetch.rb +0 -50
  121. data/test/test_launcher.rb +0 -95
  122. data/test/test_logging.rb +0 -35
  123. data/test/test_manager.rb +0 -50
  124. data/test/test_middleware.rb +0 -158
  125. data/test/test_processor.rb +0 -201
  126. data/test/test_rails.rb +0 -22
  127. data/test/test_redis_connection.rb +0 -132
  128. data/test/test_retry.rb +0 -326
  129. data/test/test_retry_exhausted.rb +0 -149
  130. data/test/test_scheduled.rb +0 -115
  131. data/test/test_scheduling.rb +0 -50
  132. data/test/test_sidekiq.rb +0 -107
  133. data/test/test_testing.rb +0 -143
  134. data/test/test_testing_fake.rb +0 -357
  135. data/test/test_testing_inline.rb +0 -94
  136. data/test/test_util.rb +0 -13
  137. data/test/test_web.rb +0 -666
  138. data/test/test_web_helpers.rb +0 -54
data/lib/sidekiq/cli.rb CHANGED
@@ -1,216 +1,259 @@
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)
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
+ 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
59
57
  end
60
- rescue ArgumentError
61
- puts "Signal #{sig} not supported"
58
+ self_write.puts(sig)
62
59
  end
60
+ rescue ArgumentError
61
+ puts "Signal #{sig} not supported"
63
62
  end
64
63
 
65
64
  logger.info "Running in #{RUBY_DESCRIPTION}"
66
65
  logger.info Sidekiq::LICENSE
67
- 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)
68
67
 
69
68
  # touch the connection pool so it is created before we
70
69
  # 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'
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
91
+
92
+ # cache process identity
93
+ Sidekiq.options[:identity] = identity
73
94
 
74
95
  # Touch middleware so it isn't lazy loaded by multiple threads, #3043
75
96
  Sidekiq.server_middleware
76
97
 
77
98
  # Before this point, the process is initializing with just the main thread.
78
99
  # Starting here the process will now have multiple threads running.
79
- fire_event(:startup)
100
+ fire_event(:startup, reverse: false, reraise: true)
80
101
 
81
- logger.debug { "Client Middleware: #{Sidekiq.client_middleware.map(&:klass).join(', ')}" }
82
- 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(", ")}" }
83
104
 
84
- if !options[:daemon]
85
- 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"
86
111
  end
87
112
 
88
- require 'sidekiq/launcher'
89
113
  @launcher = Sidekiq::Launcher.new(options)
90
114
 
91
115
  begin
92
116
  launcher.run
93
117
 
94
- while readable_io = IO.select([self_read])
118
+ while (readable_io = IO.select([self_read]))
95
119
  signal = readable_io.first[0].gets.strip
96
120
  handle_signal(signal)
97
121
  end
98
122
  rescue Interrupt
99
- logger.info 'Shutting down'
123
+ logger.info "Shutting down"
100
124
  launcher.stop
101
- # Explicitly exit so busy Processor threads can't block
102
- # process shutdown.
103
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.
104
132
  exit(0)
105
133
  end
106
134
  end
107
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
+
108
152
  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
- }
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}}
123
167
  end
124
168
 
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'
169
+ SIGNAL_HANDLERS = {
170
+ # Ctrl-C in terminal
171
+ "INT" => ->(cli) { raise Interrupt },
172
+ # TERM is the signal that Sidekiq must exit.
173
+ # Heroku sends TERM and then waits 30 seconds for process to exit.
174
+ "TERM" => ->(cli) { raise Interrupt },
175
+ "TSTP" => ->(cli) {
176
+ Sidekiq.logger.info "Received TSTP, no longer accepting new work"
177
+ cli.launcher.quiet
178
+ },
179
+ "TTIN" => ->(cli) {
144
180
  Thread.list.each do |thread|
145
- Sidekiq.logger.warn "Thread TID-#{thread.object_id.to_s(36)} #{thread['label']}"
181
+ Sidekiq.logger.warn "Thread TID-#{(thread.object_id ^ ::Process.pid).to_s(36)} #{thread.name}"
146
182
  if thread.backtrace
147
183
  Sidekiq.logger.warn thread.backtrace.join("\n")
148
184
  else
149
185
  Sidekiq.logger.warn "<no backtrace available>"
150
186
  end
151
187
  end
152
- end
188
+ }
189
+ }
190
+ UNHANDLED_SIGNAL_HANDLER = ->(cli) { Sidekiq.logger.info "No signal handler registered, ignoring" }
191
+ SIGNAL_HANDLERS.default = UNHANDLED_SIGNAL_HANDLER
192
+
193
+ def handle_signal(sig)
194
+ Sidekiq.logger.debug "Got #{sig} signal"
195
+ SIGNAL_HANDLERS[sig].call(self)
153
196
  end
154
197
 
155
198
  private
156
199
 
157
200
  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
201
+ puts "\e[31m"
202
+ puts Sidekiq::CLI.banner
203
+ puts "\e[0m"
164
204
  end
165
205
 
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
206
+ def set_environment(cli_env)
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"
194
212
  end
195
213
 
196
- def set_environment(cli_env)
197
- @environment = cli_env || ENV['RAILS_ENV'] || ENV['RACK_ENV'] || 'development'
214
+ def symbolize_keys_deep!(hash)
215
+ hash.keys.each do |k|
216
+ symkey = k.respond_to?(:to_sym) ? k.to_sym : k
217
+ hash[symkey] = hash.delete k
218
+ symbolize_keys_deep! hash[symkey] if hash[symkey].is_a? Hash
219
+ end
198
220
  end
199
221
 
200
222
  alias_method :die, :exit
201
223
  alias_method :☠, :exit
202
224
 
203
225
  def setup_options(args)
226
+ # parse CLI options
204
227
  opts = parse_options(args)
228
+
205
229
  set_environment opts[:environment]
206
230
 
207
- cfile = opts[:config_file]
208
- 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
209
242
 
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
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
213
248
 
249
+ # parse config file options
250
+ opts = parse_config(opts[:config_file]).merge(opts) if opts[:config_file]
251
+
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"]
255
+
256
+ # merge with defaults
214
257
  options.merge!(opts)
215
258
  end
216
259
 
@@ -218,44 +261,29 @@ module Sidekiq
218
261
  Sidekiq.options
219
262
  end
220
263
 
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])
264
+ def boot_application
265
+ ENV["RACK_ENV"] = ENV["RAILS_ENV"] = environment
225
266
 
226
267
  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")
268
+ require "rails"
269
+ if ::Rails::VERSION::MAJOR < 5
270
+ raise "Sidekiq no longer supports this version of Rails"
240
271
  else
241
- require 'sidekiq/rails'
272
+ require "sidekiq/rails"
242
273
  require File.expand_path("#{options[:require]}/config/environment.rb")
243
- Sidekiq.options[:reloader] = Sidekiq::Rails::Reloader.new
244
274
  end
245
275
  options[:tag] ||= default_tag
246
276
  else
247
- not_required_message = "#{options[:require]} was not required, you should use an explicit path: " +
248
- "./#{options[:require]} or /path/to/#{options[:require]}"
249
-
250
- require(options[:require]) || raise(ArgumentError, not_required_message)
277
+ require options[:require]
251
278
  end
252
279
  end
253
280
 
254
281
  def default_tag
255
282
  dir = ::Rails.root
256
283
  name = File.basename(dir)
257
- if name.to_i != 0 && prevdir = File.dirname(dir) # Capistrano release directory?
258
- 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"
259
287
  return File.basename(File.dirname(prevdir))
260
288
  end
261
289
  end
@@ -263,12 +291,10 @@ module Sidekiq
263
291
  end
264
292
 
265
293
  def validate!
266
- options[:queues] << 'default' if options[:queues].empty?
267
-
268
294
  if !File.exist?(options[:require]) ||
269
- (File.directory?(options[:require]) && !File.exist?("#{options[:require]}/config/application.rb"))
295
+ (File.directory?(options[:require]) && !File.exist?("#{options[:require]}/config/application.rb"))
270
296
  logger.info "=================================================================="
271
- logger.info " Please point sidekiq to a Rails 3/4 application or a Ruby file "
297
+ logger.info " Please point Sidekiq to a Rails application or a Ruby file "
272
298
  logger.info " to load your worker classes with -r [DIR|FILE]."
273
299
  logger.info "=================================================================="
274
300
  logger.info @parser
@@ -276,44 +302,45 @@ module Sidekiq
276
302
  end
277
303
 
278
304
  [:concurrency, :timeout].each do |opt|
279
- 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
280
306
  end
281
307
  end
282
308
 
283
309
  def parse_options(argv)
284
310
  opts = {}
311
+ @parser = option_parser(opts)
312
+ @parser.parse!(argv)
313
+ opts
314
+ end
285
315
 
286
- @parser = OptionParser.new do |o|
287
- 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|
288
319
  opts[:concurrency] = Integer(arg)
289
320
  end
290
321
 
291
- o.on '-d', '--daemon', "Daemonize process" do |arg|
292
- 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"
293
324
  end
294
325
 
295
- o.on '-e', '--environment ENV', "Application environment" do |arg|
326
+ o.on "-e", "--environment ENV", "Application environment" do |arg|
296
327
  opts[:environment] = arg
297
328
  end
298
329
 
299
- o.on '-g', '--tag TAG', "Process tag for procline" do |arg|
330
+ o.on "-g", "--tag TAG", "Process tag for procline" do |arg|
300
331
  opts[:tag] = arg
301
332
  end
302
333
 
303
- o.on '-i', '--index INT', "unique process index on this machine" do |arg|
304
- opts[:index] = Integer(arg.match(/\d+/)[0])
305
- end
306
-
307
334
  o.on "-q", "--queue QUEUE[,WEIGHT]", "Queues to process with optional weights" do |arg|
308
335
  queue, weight = arg.split(",")
309
336
  parse_queue opts, queue, weight
310
337
  end
311
338
 
312
- 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|
313
340
  opts[:require] = arg
314
341
  end
315
342
 
316
- o.on '-t', '--timeout NUM', "Shutdown timeout" do |arg|
343
+ o.on "-t", "--timeout NUM", "Shutdown timeout" do |arg|
317
344
  opts[:timeout] = Integer(arg)
318
345
  end
319
346
 
@@ -321,69 +348,51 @@ module Sidekiq
321
348
  opts[:verbose] = arg
322
349
  end
323
350
 
324
- 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|
325
352
  opts[:config_file] = arg
326
353
  end
327
354
 
328
- o.on '-L', '--logfile PATH', "path to writable logfile" do |arg|
329
- 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"
330
357
  end
331
358
 
332
- o.on '-P', '--pidfile PATH', "path to pidfile" do |arg|
333
- 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"
334
361
  end
335
362
 
336
- o.on '-V', '--version', "Print version and exit" do |arg|
363
+ o.on "-V", "--version", "Print version and exit" do |arg|
337
364
  puts "Sidekiq #{Sidekiq::VERSION}"
338
365
  die(0)
339
366
  end
340
- end
367
+ }
341
368
 
342
- @parser.banner = "sidekiq [options]"
343
- @parser.on_tail "-h", "--help", "Show help" do
344
- logger.info @parser
369
+ parser.banner = "sidekiq [options]"
370
+ parser.on_tail "-h", "--help", "Show help" do
371
+ logger.info parser
345
372
  die 1
346
373
  end
347
- @parser.parse!(argv)
348
374
 
349
- %w[config/sidekiq.yml config/sidekiq.yml.erb].each do |filename|
350
- opts[:config_file] ||= filename if File.exist?(filename)
351
- end
352
-
353
- opts
375
+ parser
354
376
  end
355
377
 
356
378
  def initialize_logger
357
- Sidekiq::Logging.initialize_logger(options[:logfile]) if options[:logfile]
358
-
359
379
  Sidekiq.logger.level = ::Logger::DEBUG if options[:verbose]
360
380
  end
361
381
 
362
- def write_pid
363
- if path = options[:pidfile]
364
- pidfile = File.expand_path(path)
365
- File.open(pidfile, 'w') do |f|
366
- f.puts ::Process.pid
367
- end
368
- end
369
- end
382
+ def parse_config(path)
383
+ opts = YAML.load(ERB.new(File.read(path)).result) || {}
370
384
 
371
- def parse_config(cfile)
372
- opts = {}
373
- if File.exist?(cfile)
374
- opts = YAML.load(ERB.new(IO.read(cfile)).result) || opts
375
- opts = opts.merge(opts.delete(environment) || {})
376
- parse_queues(opts, opts.delete(:queues) || [])
385
+ if opts.respond_to? :deep_symbolize_keys!
386
+ opts.deep_symbolize_keys!
377
387
  else
378
- # allow a non-existent config file so Sidekiq
379
- # can be deployed by cap with just the defaults.
380
- end
381
- ns = opts.delete(:namespace)
382
- if ns
383
- # logger hasn't been initialized yet, puts is all we have.
384
- puts("namespace should be set in your ruby initializer, is ignored in config file")
385
- puts("config.redis = { :url => ..., :namespace => '#{ns}' }")
388
+ symbolize_keys_deep!(opts)
386
389
  end
390
+
391
+ opts = opts.merge(opts.delete(environment.to_sym) || {})
392
+ opts.delete(:strict)
393
+
394
+ parse_queues(opts, opts.delete(:queues) || [])
395
+
387
396
  opts
388
397
  end
389
398
 
@@ -391,11 +400,18 @@ module Sidekiq
391
400
  queues_and_weights.each { |queue_and_weight| parse_queue(opts, *queue_and_weight) }
392
401
  end
393
402
 
394
- def parse_queue(opts, q, weight=nil)
395
- [weight.to_i, 1].max.times do
396
- (opts[:queues] ||= []) << q
397
- end
403
+ def parse_queue(opts, queue, weight = nil)
404
+ opts[:queues] ||= []
405
+ opts[:strict] = true if opts[:strict].nil?
406
+ raise ArgumentError, "queues: #{queue} cannot be defined twice" if opts[:queues].include?(queue)
407
+ [weight.to_i, 1].max.times { opts[:queues] << queue.to_s }
398
408
  opts[:strict] = false if weight.to_i > 0
399
409
  end
410
+
411
+ def rails_app?
412
+ defined?(::Rails) && ::Rails.respond_to?(:application)
413
+ end
400
414
  end
401
415
  end
416
+
417
+ require "sidekiq/systemd"