sidekiq 4.2.10 → 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 (75) hide show
  1. checksums.yaml +5 -5
  2. data/.circleci/config.yml +61 -0
  3. data/.github/issue_template.md +3 -1
  4. data/.gitignore +3 -0
  5. data/.travis.yml +6 -13
  6. data/5.0-Upgrade.md +56 -0
  7. data/COMM-LICENSE +12 -10
  8. data/Changes.md +177 -1
  9. data/Ent-Changes.md +67 -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 +133 -2
  14. data/README.md +8 -6
  15. data/Rakefile +2 -5
  16. data/bin/sidekiqctl +13 -92
  17. data/bin/sidekiqload +5 -10
  18. data/lib/generators/sidekiq/templates/worker_spec.rb.erb +1 -1
  19. data/lib/sidekiq/api.rb +148 -58
  20. data/lib/sidekiq/cli.rb +120 -81
  21. data/lib/sidekiq/client.rb +25 -18
  22. data/lib/sidekiq/core_ext.rb +1 -119
  23. data/lib/sidekiq/ctl.rb +221 -0
  24. data/lib/sidekiq/delay.rb +42 -0
  25. data/lib/sidekiq/exception_handler.rb +2 -4
  26. data/lib/sidekiq/extensions/generic_proxy.rb +7 -1
  27. data/lib/sidekiq/fetch.rb +1 -1
  28. data/lib/sidekiq/job_logger.rb +25 -0
  29. data/lib/sidekiq/job_retry.rb +262 -0
  30. data/lib/sidekiq/launcher.rb +20 -20
  31. data/lib/sidekiq/logging.rb +18 -2
  32. data/lib/sidekiq/manager.rb +5 -6
  33. data/lib/sidekiq/middleware/server/active_record.rb +10 -0
  34. data/lib/sidekiq/processor.rb +126 -48
  35. data/lib/sidekiq/rails.rb +8 -73
  36. data/lib/sidekiq/redis_connection.rb +43 -5
  37. data/lib/sidekiq/scheduled.rb +35 -8
  38. data/lib/sidekiq/testing.rb +16 -7
  39. data/lib/sidekiq/util.rb +5 -2
  40. data/lib/sidekiq/version.rb +1 -1
  41. data/lib/sidekiq/web/action.rb +3 -7
  42. data/lib/sidekiq/web/application.rb +37 -17
  43. data/lib/sidekiq/web/helpers.rb +69 -22
  44. data/lib/sidekiq/web/router.rb +10 -10
  45. data/lib/sidekiq/web.rb +4 -4
  46. data/lib/sidekiq/worker.rb +118 -19
  47. data/lib/sidekiq.rb +27 -27
  48. data/sidekiq.gemspec +6 -17
  49. data/web/assets/javascripts/application.js +0 -0
  50. data/web/assets/javascripts/dashboard.js +32 -17
  51. data/web/assets/stylesheets/application-rtl.css +246 -0
  52. data/web/assets/stylesheets/application.css +371 -6
  53. data/web/assets/stylesheets/bootstrap-rtl.min.css +9 -0
  54. data/web/assets/stylesheets/bootstrap.css +2 -2
  55. data/web/locales/ar.yml +81 -0
  56. data/web/locales/en.yml +2 -0
  57. data/web/locales/es.yml +4 -3
  58. data/web/locales/fa.yml +1 -0
  59. data/web/locales/he.yml +79 -0
  60. data/web/locales/ja.yml +5 -3
  61. data/web/locales/ur.yml +80 -0
  62. data/web/views/_footer.erb +5 -2
  63. data/web/views/_nav.erb +4 -18
  64. data/web/views/_paging.erb +1 -1
  65. data/web/views/busy.erb +9 -5
  66. data/web/views/dashboard.erb +1 -1
  67. data/web/views/layout.erb +11 -2
  68. data/web/views/morgue.erb +4 -4
  69. data/web/views/queue.erb +8 -7
  70. data/web/views/queues.erb +2 -0
  71. data/web/views/retries.erb +9 -5
  72. data/web/views/scheduled.erb +2 -2
  73. metadata +30 -159
  74. data/lib/sidekiq/middleware/server/logging.rb +0 -31
  75. data/lib/sidekiq/middleware/server/retry_jobs.rb +0 -205
data/lib/sidekiq/cli.rb CHANGED
@@ -1,4 +1,3 @@
1
- # encoding: utf-8
2
1
  # frozen_string_literal: true
3
2
  $stdout.sync = true
4
3
 
@@ -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 TSTP).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,60 +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 'TSTP'
139
- # USR1 is not available on JVM, allow TSTP as an alternate signal
148
+ cli.launcher.quiet
149
+ },
150
+ 'TSTP' => ->(cli) {
140
151
  Sidekiq.logger.info "Received TSTP, no longer accepting new work"
141
- launcher.quiet
142
- when 'USR2'
152
+ cli.launcher.quiet
153
+ },
154
+ 'USR2' => ->(cli) {
143
155
  if Sidekiq.options[:logfile]
144
156
  Sidekiq.logger.info "Received USR2, reopening log file"
145
157
  Sidekiq::Logging.reopen_logs
146
158
  end
147
- when 'TTIN'
159
+ },
160
+ 'TTIN' => ->(cli) {
148
161
  Thread.list.each do |thread|
149
- Sidekiq.logger.warn "Thread TID-#{thread.object_id.to_s(36)} #{thread['sidekiq_label']}"
162
+ Sidekiq.logger.warn "Thread TID-#{(thread.object_id ^ ::Process.pid).to_s(36)} #{thread['sidekiq_label']}"
150
163
  if thread.backtrace
151
164
  Sidekiq.logger.warn thread.backtrace.join("\n")
152
165
  else
153
166
  Sidekiq.logger.warn "<no backtrace available>"
154
167
  end
155
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}" }
156
179
  end
157
180
  end
158
181
 
159
182
  private
160
183
 
161
184
  def print_banner
162
- # Print logo and banner for development
163
- if environment == 'development' && $stdout.tty?
164
- puts "\e[#{31}m"
165
- puts Sidekiq::CLI.banner
166
- puts "\e[0m"
167
- end
185
+ puts "\e[#{31}m"
186
+ puts Sidekiq::CLI.banner
187
+ puts "\e[0m"
168
188
  end
169
189
 
170
190
  def daemonize
171
- return unless options[:daemon]
172
-
173
191
  raise ArgumentError, "You really should set a logfile if you're going to daemonize" unless options[:logfile]
174
- files_to_reopen = []
175
- ObjectSpace.each_object(File) do |file|
176
- files_to_reopen << file unless file.closed?
177
- end
178
192
 
193
+ files_to_reopen = ObjectSpace.each_object(File).reject { |f| f.closed? }
179
194
  ::Process.daemon(true, true)
180
195
 
181
196
  files_to_reopen.each do |file|
@@ -201,20 +216,50 @@ module Sidekiq
201
216
  @environment = cli_env || ENV['RAILS_ENV'] || ENV['RACK_ENV'] || 'development'
202
217
  end
203
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
+
204
227
  alias_method :die, :exit
205
228
  alias_method :☠, :exit
206
229
 
207
230
  def setup_options(args)
231
+ # parse CLI options
208
232
  opts = parse_options(args)
233
+
209
234
  set_environment opts[:environment]
210
235
 
211
- cfile = opts[:config_file]
212
- 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]
213
256
 
257
+ # set defaults
258
+ opts[:queues] = Array(opts[:queues]) << 'default' if opts[:queues].nil? || opts[:queues].empty?
214
259
  opts[:strict] = true if opts[:strict].nil?
215
- opts[:concurrency] = Integer(ENV["RAILS_MAX_THREADS"]) if !opts[:concurrency] && ENV["RAILS_MAX_THREADS"]
216
- opts[:identity] = identity
260
+ opts[:concurrency] = Integer(ENV["RAILS_MAX_THREADS"]) if opts[:concurrency].nil? && ENV["RAILS_MAX_THREADS"]
217
261
 
262
+ # merge with defaults
218
263
  options.merge!(opts)
219
264
  end
220
265
 
@@ -225,14 +270,10 @@ module Sidekiq
225
270
  def boot_system
226
271
  ENV['RACK_ENV'] = ENV['RAILS_ENV'] = environment
227
272
 
228
- raise ArgumentError, "#{options[:require]} does not exist" unless File.exist?(options[:require])
229
-
230
273
  if File.directory?(options[:require])
231
274
  require 'rails'
232
275
  if ::Rails::VERSION::MAJOR < 4
233
- require 'sidekiq/rails'
234
- require File.expand_path("#{options[:require]}/config/environment.rb")
235
- ::Rails.application.eager_load!
276
+ raise "Sidekiq no longer supports this version of Rails"
236
277
  elsif ::Rails::VERSION::MAJOR == 4
237
278
  # Painful contortions, see 1791 for discussion
238
279
  # No autoloading, we want to force eager load for everything.
@@ -243,16 +284,12 @@ module Sidekiq
243
284
  require 'sidekiq/rails'
244
285
  require File.expand_path("#{options[:require]}/config/environment.rb")
245
286
  else
246
- # Rails 5+ && development mode, use Reloader
247
287
  require 'sidekiq/rails'
248
288
  require File.expand_path("#{options[:require]}/config/environment.rb")
249
289
  end
250
290
  options[:tag] ||= default_tag
251
291
  else
252
- not_required_message = "#{options[:require]} was not required, you should use an explicit path: " +
253
- "./#{options[:require]} or /path/to/#{options[:require]}"
254
-
255
- require(options[:require]) || raise(ArgumentError, not_required_message)
292
+ require options[:require]
256
293
  end
257
294
  end
258
295
 
@@ -268,12 +305,10 @@ module Sidekiq
268
305
  end
269
306
 
270
307
  def validate!
271
- options[:queues] << 'default' if options[:queues].empty?
272
-
273
308
  if !File.exist?(options[:require]) ||
274
309
  (File.directory?(options[:require]) && !File.exist?("#{options[:require]}/config/application.rb"))
275
310
  logger.info "=================================================================="
276
- 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 "
277
312
  logger.info " to load your worker classes with -r [DIR|FILE]."
278
313
  logger.info "=================================================================="
279
314
  logger.info @parser
@@ -295,6 +330,7 @@ module Sidekiq
295
330
 
296
331
  o.on '-d', '--daemon', "Daemonize process" do |arg|
297
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"
298
334
  end
299
335
 
300
336
  o.on '-e', '--environment ENV', "Application environment" do |arg|
@@ -305,6 +341,8 @@ module Sidekiq
305
341
  opts[:tag] = arg
306
342
  end
307
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.
308
346
  o.on '-i', '--index INT', "unique process index on this machine" do |arg|
309
347
  opts[:index] = Integer(arg.match(/\d+/)[0])
310
348
  end
@@ -332,10 +370,12 @@ module Sidekiq
332
370
 
333
371
  o.on '-L', '--logfile PATH', "path to writable logfile" do |arg|
334
372
  opts[:logfile] = arg
373
+ puts "WARNING: Logfile redirection will be removed in Sidekiq 6.0, see #4045. Sidekiq will only log to STDOUT"
335
374
  end
336
375
 
337
376
  o.on '-P', '--pidfile PATH', "path to pidfile" do |arg|
338
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"
339
379
  end
340
380
 
341
381
  o.on '-V', '--version', "Print version and exit" do |arg|
@@ -349,11 +389,8 @@ module Sidekiq
349
389
  logger.info @parser
350
390
  die 1
351
391
  end
352
- @parser.parse!(argv)
353
392
 
354
- %w[config/sidekiq.yml config/sidekiq.yml.erb].each do |filename|
355
- opts[:config_file] ||= filename if File.exist?(filename)
356
- end
393
+ @parser.parse!(argv)
357
394
 
358
395
  opts
359
396
  end
@@ -373,16 +410,18 @@ module Sidekiq
373
410
  end
374
411
  end
375
412
 
376
- def parse_config(cfile)
377
- opts = {}
378
- if File.exist?(cfile)
379
- opts = YAML.load(ERB.new(IO.read(cfile)).result) || opts
380
- opts = opts.merge(opts.delete(environment) || {})
381
- parse_queues(opts, opts.delete(:queues) || [])
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!
382
418
  else
383
- # allow a non-existent config file so Sidekiq
384
- # can be deployed by cap with just the defaults.
419
+ symbolize_keys_deep!(opts)
385
420
  end
421
+
422
+ opts = opts.merge(opts.delete(environment.to_sym) || {})
423
+ parse_queues(opts, opts.delete(:queues) || [])
424
+
386
425
  ns = opts.delete(:namespace)
387
426
  if ns
388
427
  # logger hasn't been initialized yet, puts is all we have.
@@ -396,10 +435,10 @@ module Sidekiq
396
435
  queues_and_weights.each { |queue_and_weight| parse_queue(opts, *queue_and_weight) }
397
436
  end
398
437
 
399
- def parse_queue(opts, q, weight=nil)
400
- [weight.to_i, 1].max.times do
401
- (opts[:queues] ||= []) << q
402
- 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 }
403
442
  opts[:strict] = false if weight.to_i > 0
404
443
  end
405
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,119 +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
-
107
- begin
108
- require 'active_support/core_ext/kernel/reporting'
109
- rescue LoadError
110
- module Kernel
111
- module_function
112
- def silence_warnings
113
- old_verbose, $VERBOSE = $VERBOSE, nil
114
- yield
115
- ensure
116
- $VERBOSE = old_verbose
117
- end
118
- end
119
- end
1
+ raise "no longer used, will be removed in 5.1"