sidekiq 4.2.4 → 5.2.10

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 (108) hide show
  1. checksums.yaml +5 -5
  2. data/.circleci/config.yml +61 -0
  3. data/.github/issue_template.md +8 -1
  4. data/.gitignore +3 -0
  5. data/.travis.yml +5 -6
  6. data/5.0-Upgrade.md +56 -0
  7. data/COMM-LICENSE +12 -10
  8. data/Changes.md +220 -0
  9. data/Ent-Changes.md +94 -2
  10. data/Gemfile +12 -22
  11. data/LICENSE +1 -1
  12. data/Pro-4.0-Upgrade.md +35 -0
  13. data/Pro-Changes.md +176 -2
  14. data/README.md +10 -7
  15. data/Rakefile +3 -3
  16. data/bin/sidekiqctl +13 -92
  17. data/bin/sidekiqload +16 -34
  18. data/lib/generators/sidekiq/templates/worker_spec.rb.erb +1 -1
  19. data/lib/generators/sidekiq/templates/worker_test.rb.erb +1 -1
  20. data/lib/sidekiq/api.rb +166 -68
  21. data/lib/sidekiq/cli.rb +122 -77
  22. data/lib/sidekiq/client.rb +25 -18
  23. data/lib/sidekiq/core_ext.rb +1 -106
  24. data/lib/sidekiq/ctl.rb +221 -0
  25. data/lib/sidekiq/delay.rb +42 -0
  26. data/lib/sidekiq/exception_handler.rb +2 -4
  27. data/lib/sidekiq/extensions/generic_proxy.rb +7 -1
  28. data/lib/sidekiq/fetch.rb +1 -1
  29. data/lib/sidekiq/job_logger.rb +25 -0
  30. data/lib/sidekiq/job_retry.rb +262 -0
  31. data/lib/sidekiq/launcher.rb +49 -40
  32. data/lib/sidekiq/logging.rb +18 -2
  33. data/lib/sidekiq/manager.rb +6 -7
  34. data/lib/sidekiq/middleware/server/active_record.rb +10 -0
  35. data/lib/sidekiq/processor.rb +127 -37
  36. data/lib/sidekiq/rails.rb +16 -51
  37. data/lib/sidekiq/redis_connection.rb +50 -5
  38. data/lib/sidekiq/scheduled.rb +35 -8
  39. data/lib/sidekiq/testing.rb +24 -7
  40. data/lib/sidekiq/util.rb +6 -2
  41. data/lib/sidekiq/version.rb +1 -1
  42. data/lib/sidekiq/web/action.rb +3 -7
  43. data/lib/sidekiq/web/application.rb +38 -22
  44. data/lib/sidekiq/web/helpers.rb +78 -27
  45. data/lib/sidekiq/web/router.rb +14 -10
  46. data/lib/sidekiq/web.rb +4 -4
  47. data/lib/sidekiq/worker.rb +118 -19
  48. data/lib/sidekiq.rb +27 -26
  49. data/sidekiq.gemspec +8 -13
  50. data/web/assets/javascripts/application.js +0 -0
  51. data/web/assets/javascripts/dashboard.js +33 -18
  52. data/web/assets/stylesheets/application-rtl.css +246 -0
  53. data/web/assets/stylesheets/application.css +371 -6
  54. data/web/assets/stylesheets/bootstrap-rtl.min.css +9 -0
  55. data/web/assets/stylesheets/bootstrap.css +2 -2
  56. data/web/locales/ar.yml +81 -0
  57. data/web/locales/en.yml +2 -0
  58. data/web/locales/es.yml +4 -3
  59. data/web/locales/fa.yml +80 -0
  60. data/web/locales/he.yml +79 -0
  61. data/web/locales/ja.yml +5 -3
  62. data/web/locales/ur.yml +80 -0
  63. data/web/views/_footer.erb +5 -2
  64. data/web/views/_job_info.erb +1 -1
  65. data/web/views/_nav.erb +4 -18
  66. data/web/views/_paging.erb +1 -1
  67. data/web/views/busy.erb +9 -5
  68. data/web/views/dashboard.erb +3 -3
  69. data/web/views/layout.erb +11 -2
  70. data/web/views/morgue.erb +14 -10
  71. data/web/views/queue.erb +11 -10
  72. data/web/views/queues.erb +4 -2
  73. data/web/views/retries.erb +17 -11
  74. data/web/views/retry.erb +1 -1
  75. data/web/views/scheduled.erb +2 -2
  76. metadata +32 -151
  77. data/lib/sidekiq/middleware/server/logging.rb +0 -40
  78. data/lib/sidekiq/middleware/server/retry_jobs.rb +0 -205
  79. data/test/config.yml +0 -9
  80. data/test/env_based_config.yml +0 -11
  81. data/test/fake_env.rb +0 -1
  82. data/test/fixtures/en.yml +0 -2
  83. data/test/helper.rb +0 -75
  84. data/test/test_actors.rb +0 -138
  85. data/test/test_api.rb +0 -528
  86. data/test/test_cli.rb +0 -418
  87. data/test/test_client.rb +0 -266
  88. data/test/test_exception_handler.rb +0 -56
  89. data/test/test_extensions.rb +0 -127
  90. data/test/test_fetch.rb +0 -50
  91. data/test/test_launcher.rb +0 -95
  92. data/test/test_logging.rb +0 -35
  93. data/test/test_manager.rb +0 -50
  94. data/test/test_middleware.rb +0 -158
  95. data/test/test_processor.rb +0 -235
  96. data/test/test_rails.rb +0 -22
  97. data/test/test_redis_connection.rb +0 -132
  98. data/test/test_retry.rb +0 -326
  99. data/test/test_retry_exhausted.rb +0 -149
  100. data/test/test_scheduled.rb +0 -115
  101. data/test/test_scheduling.rb +0 -58
  102. data/test/test_sidekiq.rb +0 -107
  103. data/test/test_testing.rb +0 -143
  104. data/test/test_testing_fake.rb +0 -357
  105. data/test/test_testing_inline.rb +0 -94
  106. data/test/test_util.rb +0 -13
  107. data/test/test_web.rb +0 -726
  108. data/test/test_web_helpers.rb +0 -54
data/lib/sidekiq/cli.rb CHANGED
@@ -1,5 +1,4 @@
1
1
  # frozen_string_literal: true
2
- # encoding: utf-8
3
2
  $stdout.sync = true
4
3
 
5
4
  require 'yaml'
@@ -10,6 +9,7 @@ require 'fileutils'
10
9
 
11
10
  require 'sidekiq'
12
11
  require 'sidekiq/util'
12
+ require 'sidekiq/launcher'
13
13
 
14
14
  module Sidekiq
15
15
  class CLI
@@ -17,45 +17,47 @@ module Sidekiq
17
17
  include Singleton unless $TESTING
18
18
 
19
19
  PROCTITLES = [
20
- proc { 'sidekiq'.freeze },
20
+ proc { 'sidekiq' },
21
21
  proc { Sidekiq::VERSION },
22
22
  proc { |me, data| data['tag'] },
23
23
  proc { |me, data| "[#{Processor::WORKER_STATE.size} of #{data['concurrency']} busy]" },
24
24
  proc { |me, data| "stopping" if me.stopping? },
25
25
  ]
26
26
 
27
- # Used for CLI testing
28
- attr_accessor :code
29
27
  attr_accessor :launcher
30
28
  attr_accessor :environment
31
29
 
32
- def initialize
33
- @code = nil
34
- end
35
-
36
- def parse(args=ARGV)
37
- @code = nil
38
-
30
+ def parse(args = ARGV)
39
31
  setup_options(args)
40
32
  initialize_logger
41
33
  validate!
42
- daemonize
43
- write_pid
34
+ end
35
+
36
+ def jruby?
37
+ defined?(::JRUBY_VERSION)
44
38
  end
45
39
 
46
40
  # Code within this method is not tested because it alters
47
41
  # global process state irreversibly. PRs which improve the
48
42
  # test coverage of Sidekiq::CLI are welcomed.
49
43
  def run
44
+ daemonize if options[:daemon]
45
+ write_pid
50
46
  boot_system
51
- print_banner
47
+ print_banner if environment == 'development' && $stdout.tty?
52
48
 
53
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'
55
+ end
54
56
 
55
- %w(INT TERM USR1 USR2 TTIN).each do |sig|
57
+ sigs.each do |sig|
56
58
  begin
57
59
  trap sig do
58
- self_write.puts(sig)
60
+ self_write.write("#{sig}\n")
59
61
  end
60
62
  rescue ArgumentError
61
63
  puts "Signal #{sig} not supported"
@@ -70,22 +72,35 @@ module Sidekiq
70
72
  # fire startup and start multithreading.
71
73
  ver = Sidekiq.redis_info['redis_version']
72
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'
76
+
77
+ # Since the user can pass us a connection pool explicitly in the initializer, we
78
+ # 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
81
+ raise "Your pool of #{cursize} Redis connections is too small, please increase the size to at least #{needed}" if cursize < needed
82
+
83
+ # cache process identity
84
+ Sidekiq.options[:identity] = identity
73
85
 
74
86
  # Touch middleware so it isn't lazy loaded by multiple threads, #3043
75
87
  Sidekiq.server_middleware
76
88
 
77
89
  # Before this point, the process is initializing with just the main thread.
78
90
  # Starting here the process will now have multiple threads running.
79
- fire_event(:startup)
91
+ fire_event(:startup, reverse: false, reraise: true)
80
92
 
81
93
  logger.debug { "Client Middleware: #{Sidekiq.client_middleware.map(&:klass).join(', ')}" }
82
94
  logger.debug { "Server Middleware: #{Sidekiq.server_middleware.map(&:klass).join(', ')}" }
83
95
 
96
+ launch(self_read)
97
+ end
98
+
99
+ def launch(self_read)
84
100
  if !options[:daemon]
85
101
  logger.info 'Starting processing, hit Ctrl-C to stop'
86
102
  end
87
103
 
88
- require 'sidekiq/launcher'
89
104
  @launcher = Sidekiq::Launcher.new(options)
90
105
 
91
106
  begin
@@ -122,56 +137,60 @@ module Sidekiq
122
137
  }
123
138
  end
124
139
 
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'
140
+ SIGNAL_HANDLERS = {
141
+ # Ctrl-C in terminal
142
+ 'INT' => ->(cli) { raise Interrupt },
143
+ # TERM is the signal that Sidekiq must exit.
144
+ # Heroku sends TERM and then waits 30 seconds for process to exit.
145
+ 'TERM' => ->(cli) { raise Interrupt },
146
+ 'USR1' => ->(cli) {
136
147
  Sidekiq.logger.info "Received USR1, no longer accepting new work"
137
- launcher.quiet
138
- when 'USR2'
148
+ cli.launcher.quiet
149
+ },
150
+ 'TSTP' => ->(cli) {
151
+ Sidekiq.logger.info "Received TSTP, no longer accepting new work"
152
+ cli.launcher.quiet
153
+ },
154
+ 'USR2' => ->(cli) {
139
155
  if Sidekiq.options[:logfile]
140
156
  Sidekiq.logger.info "Received USR2, reopening log file"
141
157
  Sidekiq::Logging.reopen_logs
142
158
  end
143
- when 'TTIN'
159
+ },
160
+ 'TTIN' => ->(cli) {
144
161
  Thread.list.each do |thread|
145
- Sidekiq.logger.warn "Thread TID-#{thread.object_id.to_s(36)} #{thread['label']}"
162
+ Sidekiq.logger.warn "Thread TID-#{(thread.object_id ^ ::Process.pid).to_s(36)} #{thread['sidekiq_label']}"
146
163
  if thread.backtrace
147
164
  Sidekiq.logger.warn thread.backtrace.join("\n")
148
165
  else
149
166
  Sidekiq.logger.warn "<no backtrace available>"
150
167
  end
151
168
  end
169
+ },
170
+ }
171
+
172
+ 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}" }
152
179
  end
153
180
  end
154
181
 
155
182
  private
156
183
 
157
184
  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
185
+ puts "\e[#{31}m"
186
+ puts Sidekiq::CLI.banner
187
+ puts "\e[0m"
164
188
  end
165
189
 
166
190
  def daemonize
167
- return unless options[:daemon]
168
-
169
191
  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
192
 
193
+ files_to_reopen = ObjectSpace.each_object(File).reject { |f| f.closed? }
175
194
  ::Process.daemon(true, true)
176
195
 
177
196
  files_to_reopen.each do |file|
@@ -197,20 +216,50 @@ module Sidekiq
197
216
  @environment = cli_env || ENV['RAILS_ENV'] || ENV['RACK_ENV'] || 'development'
198
217
  end
199
218
 
219
+ def symbolize_keys_deep!(hash)
220
+ hash.keys.each do |k|
221
+ symkey = k.respond_to?(:to_sym) ? k.to_sym : k
222
+ hash[symkey] = hash.delete k
223
+ symbolize_keys_deep! hash[symkey] if hash[symkey].kind_of? Hash
224
+ end
225
+ end
226
+
200
227
  alias_method :die, :exit
201
228
  alias_method :☠, :exit
202
229
 
203
230
  def setup_options(args)
231
+ # parse CLI options
204
232
  opts = parse_options(args)
233
+
205
234
  set_environment opts[:environment]
206
235
 
207
- cfile = opts[:config_file]
208
- opts = parse_config(cfile).merge(opts) if cfile
236
+ # check config file presence
237
+ if opts[:config_file]
238
+ if opts[:config_file] && !File.exist?(opts[:config_file])
239
+ raise ArgumentError, "No such file #{opts[:config_file]}"
240
+ end
241
+ else
242
+ config_dir = if File.directory?(opts[:require].to_s)
243
+ File.join(opts[:require], 'config')
244
+ else
245
+ File.join(options[:require], 'config')
246
+ end
247
+
248
+ %w[sidekiq.yml sidekiq.yml.erb].each do |config_file|
249
+ path = File.join(config_dir, config_file)
250
+ opts[:config_file] ||= path if File.exist?(path)
251
+ end
252
+ end
253
+
254
+ # parse config file options
255
+ opts = parse_config(opts[:config_file]).merge(opts) if opts[:config_file]
209
256
 
257
+ # set defaults
258
+ opts[:queues] = Array(opts[:queues]) << 'default' if opts[:queues].nil? || opts[:queues].empty?
210
259
  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
260
+ opts[:concurrency] = Integer(ENV["RAILS_MAX_THREADS"]) if opts[:concurrency].nil? && ENV["RAILS_MAX_THREADS"]
213
261
 
262
+ # merge with defaults
214
263
  options.merge!(opts)
215
264
  end
216
265
 
@@ -221,16 +270,13 @@ module Sidekiq
221
270
  def boot_system
222
271
  ENV['RACK_ENV'] = ENV['RAILS_ENV'] = environment
223
272
 
224
- raise ArgumentError, "#{options[:require]} does not exist" unless File.exist?(options[:require])
225
-
226
273
  if File.directory?(options[:require])
227
274
  require 'rails'
228
275
  if ::Rails::VERSION::MAJOR < 4
229
- require 'sidekiq/rails'
230
- require File.expand_path("#{options[:require]}/config/environment.rb")
231
- ::Rails.application.eager_load!
276
+ raise "Sidekiq no longer supports this version of Rails"
232
277
  elsif ::Rails::VERSION::MAJOR == 4
233
278
  # Painful contortions, see 1791 for discussion
279
+ # No autoloading, we want to force eager load for everything.
234
280
  require File.expand_path("#{options[:require]}/config/application.rb")
235
281
  ::Rails::Application.initializer "sidekiq.eager_load" do
236
282
  ::Rails.application.config.eager_load = true
@@ -243,10 +289,7 @@ module Sidekiq
243
289
  end
244
290
  options[:tag] ||= default_tag
245
291
  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)
292
+ require options[:require]
250
293
  end
251
294
  end
252
295
 
@@ -262,12 +305,10 @@ module Sidekiq
262
305
  end
263
306
 
264
307
  def validate!
265
- options[:queues] << 'default' if options[:queues].empty?
266
-
267
308
  if !File.exist?(options[:require]) ||
268
309
  (File.directory?(options[:require]) && !File.exist?("#{options[:require]}/config/application.rb"))
269
310
  logger.info "=================================================================="
270
- logger.info " Please point sidekiq to a Rails 3/4 application or a Ruby file "
311
+ logger.info " Please point sidekiq to a Rails 4/5 application or a Ruby file "
271
312
  logger.info " to load your worker classes with -r [DIR|FILE]."
272
313
  logger.info "=================================================================="
273
314
  logger.info @parser
@@ -289,6 +330,7 @@ module Sidekiq
289
330
 
290
331
  o.on '-d', '--daemon', "Daemonize process" do |arg|
291
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"
292
334
  end
293
335
 
294
336
  o.on '-e', '--environment ENV', "Application environment" do |arg|
@@ -299,6 +341,8 @@ module Sidekiq
299
341
  opts[:tag] = arg
300
342
  end
301
343
 
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.
302
346
  o.on '-i', '--index INT', "unique process index on this machine" do |arg|
303
347
  opts[:index] = Integer(arg.match(/\d+/)[0])
304
348
  end
@@ -326,10 +370,12 @@ module Sidekiq
326
370
 
327
371
  o.on '-L', '--logfile PATH', "path to writable logfile" do |arg|
328
372
  opts[:logfile] = arg
373
+ puts "WARNING: Logfile redirection will be removed in Sidekiq 6.0, see #4045. Sidekiq will only log to STDOUT"
329
374
  end
330
375
 
331
376
  o.on '-P', '--pidfile PATH', "path to pidfile" do |arg|
332
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"
333
379
  end
334
380
 
335
381
  o.on '-V', '--version', "Print version and exit" do |arg|
@@ -343,11 +389,8 @@ module Sidekiq
343
389
  logger.info @parser
344
390
  die 1
345
391
  end
346
- @parser.parse!(argv)
347
392
 
348
- %w[config/sidekiq.yml config/sidekiq.yml.erb].each do |filename|
349
- opts[:config_file] ||= filename if File.exist?(filename)
350
- end
393
+ @parser.parse!(argv)
351
394
 
352
395
  opts
353
396
  end
@@ -367,16 +410,18 @@ module Sidekiq
367
410
  end
368
411
  end
369
412
 
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) || [])
413
+ def parse_config(path)
414
+ opts = YAML.load(ERB.new(File.read(path)).result) || {}
415
+
416
+ if opts.respond_to? :deep_symbolize_keys!
417
+ opts.deep_symbolize_keys!
376
418
  else
377
- # allow a non-existent config file so Sidekiq
378
- # can be deployed by cap with just the defaults.
419
+ symbolize_keys_deep!(opts)
379
420
  end
421
+
422
+ opts = opts.merge(opts.delete(environment.to_sym) || {})
423
+ parse_queues(opts, opts.delete(:queues) || [])
424
+
380
425
  ns = opts.delete(:namespace)
381
426
  if ns
382
427
  # logger hasn't been initialized yet, puts is all we have.
@@ -390,10 +435,10 @@ module Sidekiq
390
435
  queues_and_weights.each { |queue_and_weight| parse_queue(opts, *queue_and_weight) }
391
436
  end
392
437
 
393
- def parse_queue(opts, q, weight=nil)
394
- [weight.to_i, 1].max.times do
395
- (opts[:queues] ||= []) << q
396
- end
438
+ def parse_queue(opts, queue, weight = nil)
439
+ opts[:queues] ||= []
440
+ raise ArgumentError, "queues: #{queue} cannot be defined twice" if opts[:queues].include?(queue)
441
+ [weight.to_i, 1].max.times { opts[:queues] << queue }
397
442
  opts[:strict] = false if weight.to_i > 0
398
443
  end
399
444
  end
@@ -48,9 +48,15 @@ module Sidekiq
48
48
  # queue - the named queue to use, default 'default'
49
49
  # class - the worker class to call, required
50
50
  # args - an array of simple arguments to the perform method, must be JSON-serializable
51
+ # at - timestamp to schedule the job (optional), must be Numeric (e.g. Time.now.to_f)
51
52
  # retry - whether to retry this job if it fails, default true or an integer number of retries
52
53
  # backtrace - whether to save any error backtrace, default false
53
54
  #
55
+ # If class is set to the class name, the jobs' options will be based on Sidekiq's default
56
+ # worker options. Otherwise, they will be based on the job class's options.
57
+ #
58
+ # Any options valid for a worker class's sidekiq_options are also available here.
59
+ #
54
60
  # All options must be strings, not symbols. NB: because we are serializing to JSON, all
55
61
  # symbols in 'args' will be converted to strings. Note that +backtrace: true+ can take quite a bit of
56
62
  # space in Redis; a large volume of failing jobs can start Redis swapping if you aren't careful.
@@ -71,9 +77,10 @@ module Sidekiq
71
77
  end
72
78
 
73
79
  ##
74
- # Push a large number of jobs to Redis. In practice this method is only
75
- # useful if you are pushing thousands of jobs or more. This method
76
- # cuts out the redis network round trip latency.
80
+ # Push a large number of jobs to Redis. This method cuts out the redis
81
+ # network round trip latency. I wouldn't recommend pushing more than
82
+ # 1000 per call but YMMV based on network quality, size of job args, etc.
83
+ # A large number of jobs can cause a bit of Redis command processing latency.
77
84
  #
78
85
  # Takes the same arguments as #push except that args is expected to be
79
86
  # an Array of Arrays. All other keys are duplicated for each job. Each job
@@ -113,11 +120,10 @@ module Sidekiq
113
120
  def self.via(pool)
114
121
  raise ArgumentError, "No pool given" if pool.nil?
115
122
  current_sidekiq_pool = Thread.current[:sidekiq_via_pool]
116
- raise RuntimeError, "Sidekiq::Client.via is not re-entrant" if current_sidekiq_pool && current_sidekiq_pool != pool
117
123
  Thread.current[:sidekiq_via_pool] = pool
118
124
  yield
119
125
  ensure
120
- Thread.current[:sidekiq_via_pool] = nil
126
+ Thread.current[:sidekiq_via_pool] = current_sidekiq_pool
121
127
  end
122
128
 
123
129
  class << self
@@ -158,7 +164,7 @@ module Sidekiq
158
164
  ts = (int < 1_000_000_000 ? now + int : int)
159
165
 
160
166
  item = { 'class' => klass, 'args' => args, 'at' => ts, 'queue' => queue }
161
- item.delete('at'.freeze) if ts <= now
167
+ item.delete('at') if ts <= now
162
168
 
163
169
  klass.client_push(item)
164
170
  end
@@ -184,18 +190,18 @@ module Sidekiq
184
190
 
185
191
  def atomic_push(conn, payloads)
186
192
  if payloads.first['at']
187
- conn.zadd('schedule'.freeze, payloads.map do |hash|
188
- at = hash.delete('at'.freeze).to_s
193
+ conn.zadd('schedule', payloads.map do |hash|
194
+ at = hash.delete('at').to_s
189
195
  [at, Sidekiq.dump_json(hash)]
190
196
  end)
191
197
  else
192
198
  q = payloads.first['queue']
193
199
  now = Time.now.to_f
194
200
  to_push = payloads.map do |entry|
195
- entry['enqueued_at'.freeze] = now
201
+ entry['enqueued_at'] = now
196
202
  Sidekiq.dump_json(entry)
197
203
  end
198
- conn.sadd('queues'.freeze, q)
204
+ conn.sadd('queues', q)
199
205
  conn.lpush("queue:#{q}", to_push)
200
206
  end
201
207
  end
@@ -209,24 +215,25 @@ module Sidekiq
209
215
  end
210
216
 
211
217
  def normalize_item(item)
212
- raise(ArgumentError, "Job must be a Hash with 'class' and 'args' keys: { 'class' => SomeWorker, 'args' => ['bob', 1, :foo => 'bar'] }") unless item.is_a?(Hash) && item.has_key?('class'.freeze) && item.has_key?('args'.freeze)
218
+ raise(ArgumentError, "Job must be a Hash with 'class' and 'args' keys: { 'class' => SomeWorker, 'args' => ['bob', 1, :foo => 'bar'] }") unless item.is_a?(Hash) && item.has_key?('class') && item.has_key?('args')
213
219
  raise(ArgumentError, "Job args must be an Array") unless item['args'].is_a?(Array)
214
- raise(ArgumentError, "Job class must be either a Class or String representation of the class name") unless item['class'.freeze].is_a?(Class) || item['class'.freeze].is_a?(String)
220
+ raise(ArgumentError, "Job class must be either a Class or String representation of the class name") unless item['class'].is_a?(Class) || item['class'].is_a?(String)
221
+ raise(ArgumentError, "Job 'at' must be a Numeric timestamp") if item.has_key?('at') && !item['at'].is_a?(Numeric)
215
222
  #raise(ArgumentError, "Arguments must be native JSON types, see https://github.com/mperham/sidekiq/wiki/Best-Practices") unless JSON.load(JSON.dump(item['args'])) == item['args']
216
223
 
217
- normalized_hash(item['class'.freeze])
224
+ normalized_hash(item['class'])
218
225
  .each{ |key, value| item[key] = value if item[key].nil? }
219
226
 
220
- item['class'.freeze] = item['class'.freeze].to_s
221
- item['queue'.freeze] = item['queue'.freeze].to_s
222
- item['jid'.freeze] ||= SecureRandom.hex(12)
223
- item['created_at'.freeze] ||= Time.now.to_f
227
+ item['class'] = item['class'].to_s
228
+ item['queue'] = item['queue'].to_s
229
+ item['jid'] ||= SecureRandom.hex(12)
230
+ item['created_at'] ||= Time.now.to_f
224
231
  item
225
232
  end
226
233
 
227
234
  def normalized_hash(item_class)
228
235
  if item_class.is_a?(Class)
229
- raise(ArgumentError, "Message must include a Sidekiq::Worker class, not class name: #{item_class.ancestors.inspect}") if !item_class.respond_to?('get_sidekiq_options'.freeze)
236
+ raise(ArgumentError, "Message must include a Sidekiq::Worker class, not class name: #{item_class.ancestors.inspect}") if !item_class.respond_to?('get_sidekiq_options')
230
237
  item_class.get_sidekiq_options
231
238
  else
232
239
  Sidekiq.default_worker_options
@@ -1,106 +1 @@
1
- # frozen_string_literal: true
2
- begin
3
- require 'active_support/core_ext/class/attribute'
4
- rescue LoadError
5
-
6
- # A dumbed down version of ActiveSupport's
7
- # Class#class_attribute helper.
8
- class Class
9
- def class_attribute(*attrs)
10
- instance_writer = true
11
-
12
- attrs.each do |name|
13
- class_eval <<-RUBY, __FILE__, __LINE__ + 1
14
- def self.#{name}() nil end
15
- def self.#{name}?() !!#{name} end
16
-
17
- def self.#{name}=(val)
18
- singleton_class.class_eval do
19
- define_method(:#{name}) { val }
20
- end
21
-
22
- if singleton_class?
23
- class_eval do
24
- def #{name}
25
- defined?(@#{name}) ? @#{name} : singleton_class.#{name}
26
- end
27
- end
28
- end
29
- val
30
- end
31
-
32
- def #{name}
33
- defined?(@#{name}) ? @#{name} : self.class.#{name}
34
- end
35
-
36
- def #{name}?
37
- !!#{name}
38
- end
39
- RUBY
40
-
41
- attr_writer name if instance_writer
42
- end
43
- end
44
-
45
- private
46
- def singleton_class?
47
- ancestors.first != self
48
- end
49
- end
50
- end
51
-
52
- begin
53
- require 'active_support/core_ext/hash/keys'
54
- require 'active_support/core_ext/hash/deep_merge'
55
- rescue LoadError
56
- class Hash
57
- def stringify_keys
58
- keys.each do |key|
59
- self[key.to_s] = delete(key)
60
- end
61
- self
62
- end if !{}.respond_to?(:stringify_keys)
63
-
64
- def symbolize_keys
65
- keys.each do |key|
66
- self[(key.to_sym rescue key) || key] = delete(key)
67
- end
68
- self
69
- end if !{}.respond_to?(:symbolize_keys)
70
-
71
- def deep_merge(other_hash, &block)
72
- dup.deep_merge!(other_hash, &block)
73
- end if !{}.respond_to?(:deep_merge)
74
-
75
- def deep_merge!(other_hash, &block)
76
- other_hash.each_pair do |k,v|
77
- tv = self[k]
78
- if tv.is_a?(Hash) && v.is_a?(Hash)
79
- self[k] = tv.deep_merge(v, &block)
80
- else
81
- self[k] = block && tv ? block.call(k, tv, v) : v
82
- end
83
- end
84
- self
85
- end if !{}.respond_to?(:deep_merge!)
86
- end
87
- end
88
-
89
- begin
90
- require 'active_support/core_ext/string/inflections'
91
- rescue LoadError
92
- class String
93
- def constantize
94
- names = self.split('::')
95
- names.shift if names.empty? || names.first.empty?
96
-
97
- constant = Object
98
- names.each do |name|
99
- constant = constant.const_defined?(name) ? constant.const_get(name) : constant.const_missing(name)
100
- end
101
- constant
102
- end
103
- end if !"".respond_to?(:constantize)
104
- end
105
-
106
-
1
+ raise "no longer used, will be removed in 5.1"