sidekiq 4.2.4 → 5.2.0
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.
- checksums.yaml +4 -4
- data/.github/issue_template.md +8 -1
- data/.gitignore +1 -0
- data/.travis.yml +5 -3
- data/5.0-Upgrade.md +56 -0
- data/COMM-LICENSE +1 -1
- data/Changes.md +151 -0
- data/Ent-Changes.md +77 -2
- data/Gemfile +10 -25
- data/LICENSE +1 -1
- data/Pro-4.0-Upgrade.md +35 -0
- data/Pro-Changes.md +156 -2
- data/README.md +9 -6
- data/Rakefile +1 -2
- data/bin/sidekiqctl +1 -1
- data/bin/sidekiqload +15 -33
- data/lib/generators/sidekiq/templates/worker_spec.rb.erb +1 -1
- data/lib/generators/sidekiq/templates/worker_test.rb.erb +1 -1
- data/lib/sidekiq/api.rb +157 -67
- data/lib/sidekiq/cli.rb +71 -26
- data/lib/sidekiq/client.rb +25 -18
- data/lib/sidekiq/core_ext.rb +1 -106
- data/lib/sidekiq/delay.rb +42 -0
- data/lib/sidekiq/exception_handler.rb +2 -4
- data/lib/sidekiq/extensions/generic_proxy.rb +7 -1
- data/lib/sidekiq/fetch.rb +1 -1
- data/lib/sidekiq/job_logger.rb +25 -0
- data/lib/sidekiq/job_retry.rb +241 -0
- data/lib/sidekiq/launcher.rb +45 -37
- data/lib/sidekiq/logging.rb +18 -2
- data/lib/sidekiq/manager.rb +3 -4
- data/lib/sidekiq/middleware/server/active_record.rb +10 -0
- data/lib/sidekiq/processor.rb +91 -34
- data/lib/sidekiq/rails.rb +15 -51
- data/lib/sidekiq/redis_connection.rb +31 -5
- data/lib/sidekiq/scheduled.rb +35 -8
- data/lib/sidekiq/testing.rb +24 -7
- data/lib/sidekiq/util.rb +6 -2
- data/lib/sidekiq/version.rb +1 -1
- data/lib/sidekiq/web/action.rb +2 -6
- data/lib/sidekiq/web/application.rb +28 -21
- data/lib/sidekiq/web/helpers.rb +67 -23
- data/lib/sidekiq/web/router.rb +14 -10
- data/lib/sidekiq/web.rb +4 -4
- data/lib/sidekiq/worker.rb +97 -14
- data/lib/sidekiq.rb +23 -24
- data/sidekiq.gemspec +7 -10
- data/web/assets/javascripts/application.js +0 -0
- data/web/assets/javascripts/dashboard.js +18 -13
- data/web/assets/stylesheets/application-rtl.css +246 -0
- data/web/assets/stylesheets/application.css +336 -4
- data/web/assets/stylesheets/bootstrap-rtl.min.css +9 -0
- data/web/assets/stylesheets/bootstrap.css +2 -2
- data/web/locales/ar.yml +80 -0
- data/web/locales/en.yml +1 -0
- data/web/locales/es.yml +4 -3
- data/web/locales/fa.yml +80 -0
- data/web/locales/he.yml +79 -0
- data/web/locales/ja.yml +5 -3
- data/web/locales/ur.yml +80 -0
- data/web/views/_footer.erb +5 -2
- data/web/views/_job_info.erb +1 -1
- data/web/views/_nav.erb +1 -1
- data/web/views/_paging.erb +1 -1
- data/web/views/busy.erb +9 -5
- data/web/views/dashboard.erb +3 -3
- data/web/views/layout.erb +11 -2
- data/web/views/morgue.erb +14 -10
- data/web/views/queue.erb +10 -10
- data/web/views/queues.erb +4 -2
- data/web/views/retries.erb +13 -11
- data/web/views/retry.erb +1 -1
- data/web/views/scheduled.erb +2 -2
- metadata +26 -160
- data/lib/sidekiq/middleware/server/logging.rb +0 -40
- data/lib/sidekiq/middleware/server/retry_jobs.rb +0 -205
- data/test/config.yml +0 -9
- data/test/env_based_config.yml +0 -11
- data/test/fake_env.rb +0 -1
- data/test/fixtures/en.yml +0 -2
- data/test/helper.rb +0 -75
- data/test/test_actors.rb +0 -138
- data/test/test_api.rb +0 -528
- data/test/test_cli.rb +0 -418
- data/test/test_client.rb +0 -266
- data/test/test_exception_handler.rb +0 -56
- data/test/test_extensions.rb +0 -127
- data/test/test_fetch.rb +0 -50
- data/test/test_launcher.rb +0 -95
- data/test/test_logging.rb +0 -35
- data/test/test_manager.rb +0 -50
- data/test/test_middleware.rb +0 -158
- data/test/test_processor.rb +0 -235
- data/test/test_rails.rb +0 -22
- data/test/test_redis_connection.rb +0 -132
- data/test/test_retry.rb +0 -326
- data/test/test_retry_exhausted.rb +0 -149
- data/test/test_scheduled.rb +0 -115
- data/test/test_scheduling.rb +0 -58
- data/test/test_sidekiq.rb +0 -107
- data/test/test_testing.rb +0 -143
- data/test/test_testing_fake.rb +0 -357
- data/test/test_testing_inline.rb +0 -94
- data/test/test_util.rb +0 -13
- data/test/test_web.rb +0 -726
- 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'
|
@@ -17,7 +16,7 @@ module Sidekiq
|
|
17
16
|
include Singleton unless $TESTING
|
18
17
|
|
19
18
|
PROCTITLES = [
|
20
|
-
proc { 'sidekiq'
|
19
|
+
proc { 'sidekiq' },
|
21
20
|
proc { Sidekiq::VERSION },
|
22
21
|
proc { |me, data| data['tag'] },
|
23
22
|
proc { |me, data| "[#{Processor::WORKER_STATE.size} of #{data['concurrency']} busy]" },
|
@@ -43,6 +42,10 @@ module Sidekiq
|
|
43
42
|
write_pid
|
44
43
|
end
|
45
44
|
|
45
|
+
def jruby?
|
46
|
+
defined?(::JRUBY_VERSION)
|
47
|
+
end
|
48
|
+
|
46
49
|
# Code within this method is not tested because it alters
|
47
50
|
# global process state irreversibly. PRs which improve the
|
48
51
|
# test coverage of Sidekiq::CLI are welcomed.
|
@@ -51,11 +54,17 @@ module Sidekiq
|
|
51
54
|
print_banner
|
52
55
|
|
53
56
|
self_read, self_write = IO.pipe
|
57
|
+
sigs = %w(INT TERM TTIN TSTP)
|
58
|
+
# USR1 and USR2 don't work on the JVM
|
59
|
+
if !jruby?
|
60
|
+
sigs << 'USR1'
|
61
|
+
sigs << 'USR2'
|
62
|
+
end
|
54
63
|
|
55
|
-
|
64
|
+
sigs.each do |sig|
|
56
65
|
begin
|
57
66
|
trap sig do
|
58
|
-
self_write.
|
67
|
+
self_write.write("#{sig}\n")
|
59
68
|
end
|
60
69
|
rescue ArgumentError
|
61
70
|
puts "Signal #{sig} not supported"
|
@@ -71,12 +80,21 @@ module Sidekiq
|
|
71
80
|
ver = Sidekiq.redis_info['redis_version']
|
72
81
|
raise "You are using Redis v#{ver}, Sidekiq requires Redis v2.8.0 or greater" if ver < '2.8'
|
73
82
|
|
83
|
+
# Since the user can pass us a connection pool explicitly in the initializer, we
|
84
|
+
# need to verify the size is large enough or else Sidekiq's performance is dramatically slowed.
|
85
|
+
cursize = Sidekiq.redis_pool.size
|
86
|
+
needed = Sidekiq.options[:concurrency] + 2
|
87
|
+
raise "Your pool of #{cursize} Redis connections is too small, please increase the size to at least #{needed}" if cursize < needed
|
88
|
+
|
89
|
+
# cache process identity
|
90
|
+
Sidekiq.options[:identity] = identity
|
91
|
+
|
74
92
|
# Touch middleware so it isn't lazy loaded by multiple threads, #3043
|
75
93
|
Sidekiq.server_middleware
|
76
94
|
|
77
95
|
# Before this point, the process is initializing with just the main thread.
|
78
96
|
# Starting here the process will now have multiple threads running.
|
79
|
-
fire_event(:startup)
|
97
|
+
fire_event(:startup, reverse: false, reraise: true)
|
80
98
|
|
81
99
|
logger.debug { "Client Middleware: #{Sidekiq.client_middleware.map(&:klass).join(', ')}" }
|
82
100
|
logger.debug { "Server Middleware: #{Sidekiq.server_middleware.map(&:klass).join(', ')}" }
|
@@ -122,33 +140,45 @@ module Sidekiq
|
|
122
140
|
}
|
123
141
|
end
|
124
142
|
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
when 'TERM'
|
133
|
-
# Heroku sends TERM and then waits 10 seconds for process to exit.
|
134
|
-
raise Interrupt
|
135
|
-
when 'USR1'
|
143
|
+
SIGNAL_HANDLERS = {
|
144
|
+
# Ctrl-C in terminal
|
145
|
+
'INT' => ->(cli) { raise Interrupt },
|
146
|
+
# TERM is the signal that Sidekiq must exit.
|
147
|
+
# Heroku sends TERM and then waits 30 seconds for process to exit.
|
148
|
+
'TERM' => ->(cli) { raise Interrupt },
|
149
|
+
'USR1' => ->(cli) {
|
136
150
|
Sidekiq.logger.info "Received USR1, no longer accepting new work"
|
137
|
-
launcher.quiet
|
138
|
-
|
151
|
+
cli.launcher.quiet
|
152
|
+
},
|
153
|
+
'TSTP' => ->(cli) {
|
154
|
+
Sidekiq.logger.info "Received TSTP, no longer accepting new work"
|
155
|
+
cli.launcher.quiet
|
156
|
+
},
|
157
|
+
'USR2' => ->(cli) {
|
139
158
|
if Sidekiq.options[:logfile]
|
140
159
|
Sidekiq.logger.info "Received USR2, reopening log file"
|
141
160
|
Sidekiq::Logging.reopen_logs
|
142
161
|
end
|
143
|
-
|
162
|
+
},
|
163
|
+
'TTIN' => ->(cli) {
|
144
164
|
Thread.list.each do |thread|
|
145
|
-
Sidekiq.logger.warn "Thread TID-#{thread.object_id.to_s(36)} #{thread['
|
165
|
+
Sidekiq.logger.warn "Thread TID-#{(thread.object_id ^ ::Process.pid).to_s(36)} #{thread['sidekiq_label']}"
|
146
166
|
if thread.backtrace
|
147
167
|
Sidekiq.logger.warn thread.backtrace.join("\n")
|
148
168
|
else
|
149
169
|
Sidekiq.logger.warn "<no backtrace available>"
|
150
170
|
end
|
151
171
|
end
|
172
|
+
},
|
173
|
+
}
|
174
|
+
|
175
|
+
def handle_signal(sig)
|
176
|
+
Sidekiq.logger.debug "Got #{sig} signal"
|
177
|
+
handy = SIGNAL_HANDLERS[sig]
|
178
|
+
if handy
|
179
|
+
handy.call(self)
|
180
|
+
else
|
181
|
+
Sidekiq.logger.info { "No signal handler for #{sig}" }
|
152
182
|
end
|
153
183
|
end
|
154
184
|
|
@@ -197,6 +227,14 @@ module Sidekiq
|
|
197
227
|
@environment = cli_env || ENV['RAILS_ENV'] || ENV['RACK_ENV'] || 'development'
|
198
228
|
end
|
199
229
|
|
230
|
+
def symbolize_keys_deep!(hash)
|
231
|
+
hash.keys.each do |k|
|
232
|
+
symkey = k.respond_to?(:to_sym) ? k.to_sym : k
|
233
|
+
hash[symkey] = hash.delete k
|
234
|
+
symbolize_keys_deep! hash[symkey] if hash[symkey].kind_of? Hash
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
200
238
|
alias_method :die, :exit
|
201
239
|
alias_method :☠, :exit
|
202
240
|
|
@@ -209,7 +247,6 @@ module Sidekiq
|
|
209
247
|
|
210
248
|
opts[:strict] = true if opts[:strict].nil?
|
211
249
|
opts[:concurrency] = Integer(ENV["RAILS_MAX_THREADS"]) if !opts[:concurrency] && ENV["RAILS_MAX_THREADS"]
|
212
|
-
opts[:identity] = identity
|
213
250
|
|
214
251
|
options.merge!(opts)
|
215
252
|
end
|
@@ -226,11 +263,10 @@ module Sidekiq
|
|
226
263
|
if File.directory?(options[:require])
|
227
264
|
require 'rails'
|
228
265
|
if ::Rails::VERSION::MAJOR < 4
|
229
|
-
|
230
|
-
require File.expand_path("#{options[:require]}/config/environment.rb")
|
231
|
-
::Rails.application.eager_load!
|
266
|
+
raise "Sidekiq no longer supports this version of Rails"
|
232
267
|
elsif ::Rails::VERSION::MAJOR == 4
|
233
268
|
# Painful contortions, see 1791 for discussion
|
269
|
+
# No autoloading, we want to force eager load for everything.
|
234
270
|
require File.expand_path("#{options[:require]}/config/application.rb")
|
235
271
|
::Rails::Application.initializer "sidekiq.eager_load" do
|
236
272
|
::Rails.application.config.eager_load = true
|
@@ -267,7 +303,7 @@ module Sidekiq
|
|
267
303
|
if !File.exist?(options[:require]) ||
|
268
304
|
(File.directory?(options[:require]) && !File.exist?("#{options[:require]}/config/application.rb"))
|
269
305
|
logger.info "=================================================================="
|
270
|
-
logger.info " Please point sidekiq to a Rails
|
306
|
+
logger.info " Please point sidekiq to a Rails 4/5 application or a Ruby file "
|
271
307
|
logger.info " to load your worker classes with -r [DIR|FILE]."
|
272
308
|
logger.info "=================================================================="
|
273
309
|
logger.info @parser
|
@@ -299,6 +335,8 @@ module Sidekiq
|
|
299
335
|
opts[:tag] = arg
|
300
336
|
end
|
301
337
|
|
338
|
+
# this index remains here for backwards compatibility but none of the Sidekiq
|
339
|
+
# family use this value anymore. it was used by Pro's original reliable_fetch.
|
302
340
|
o.on '-i', '--index INT', "unique process index on this machine" do |arg|
|
303
341
|
opts[:index] = Integer(arg.match(/\d+/)[0])
|
304
342
|
end
|
@@ -371,7 +409,14 @@ module Sidekiq
|
|
371
409
|
opts = {}
|
372
410
|
if File.exist?(cfile)
|
373
411
|
opts = YAML.load(ERB.new(IO.read(cfile)).result) || opts
|
374
|
-
|
412
|
+
|
413
|
+
if opts.respond_to? :deep_symbolize_keys!
|
414
|
+
opts.deep_symbolize_keys!
|
415
|
+
else
|
416
|
+
symbolize_keys_deep!(opts)
|
417
|
+
end
|
418
|
+
|
419
|
+
opts = opts.merge(opts.delete(environment.to_sym) || {})
|
375
420
|
parse_queues(opts, opts.delete(:queues) || [])
|
376
421
|
else
|
377
422
|
# allow a non-existent config file so Sidekiq
|
data/lib/sidekiq/client.rb
CHANGED
@@ -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.
|
75
|
-
#
|
76
|
-
#
|
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] =
|
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'
|
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'
|
188
|
-
at = hash.delete('at'
|
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'
|
201
|
+
entry['enqueued_at'] = now
|
196
202
|
Sidekiq.dump_json(entry)
|
197
203
|
end
|
198
|
-
conn.sadd('queues'
|
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'
|
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'
|
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'
|
224
|
+
normalized_hash(item['class'])
|
218
225
|
.each{ |key, value| item[key] = value if item[key].nil? }
|
219
226
|
|
220
|
-
item['class'
|
221
|
-
item['queue'
|
222
|
-
item['jid'
|
223
|
-
item['created_at'
|
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'
|
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
|
data/lib/sidekiq/core_ext.rb
CHANGED
@@ -1,106 +1 @@
|
|
1
|
-
|
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"
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Sidekiq
|
3
|
+
module Extensions
|
4
|
+
|
5
|
+
def self.enable_delay!
|
6
|
+
if defined?(::ActiveSupport)
|
7
|
+
require 'sidekiq/extensions/active_record'
|
8
|
+
require 'sidekiq/extensions/action_mailer'
|
9
|
+
|
10
|
+
# Need to patch Psych so it can autoload classes whose names are serialized
|
11
|
+
# in the delayed YAML.
|
12
|
+
Psych::Visitors::ToRuby.prepend(Sidekiq::Extensions::PsychAutoload)
|
13
|
+
|
14
|
+
ActiveSupport.on_load(:active_record) do
|
15
|
+
include Sidekiq::Extensions::ActiveRecord
|
16
|
+
end
|
17
|
+
ActiveSupport.on_load(:action_mailer) do
|
18
|
+
extend Sidekiq::Extensions::ActionMailer
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
require 'sidekiq/extensions/class_methods'
|
23
|
+
Module.__send__(:include, Sidekiq::Extensions::Klass)
|
24
|
+
end
|
25
|
+
|
26
|
+
module PsychAutoload
|
27
|
+
def resolve_class(klass_name)
|
28
|
+
return nil if !klass_name || klass_name.empty?
|
29
|
+
# constantize
|
30
|
+
names = klass_name.split('::')
|
31
|
+
names.shift if names.empty? || names.first.empty?
|
32
|
+
|
33
|
+
names.inject(Object) do |constant, name|
|
34
|
+
constant.const_defined?(name) ? constant.const_get(name) : constant.const_missing(name)
|
35
|
+
end
|
36
|
+
rescue NameError
|
37
|
+
super
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
@@ -7,11 +7,10 @@ module Sidekiq
|
|
7
7
|
class Logger
|
8
8
|
def call(ex, ctxHash)
|
9
9
|
Sidekiq.logger.warn(Sidekiq.dump_json(ctxHash)) if !ctxHash.empty?
|
10
|
-
Sidekiq.logger.warn
|
11
|
-
Sidekiq.logger.warn
|
10
|
+
Sidekiq.logger.warn("#{ex.class.name}: #{ex.message}")
|
11
|
+
Sidekiq.logger.warn(ex.backtrace.join("\n")) unless ex.backtrace.nil?
|
12
12
|
end
|
13
13
|
|
14
|
-
# Set up default handler which just logs the error
|
15
14
|
Sidekiq.error_handlers << Sidekiq::ExceptionHandler::Logger.new
|
16
15
|
end
|
17
16
|
|
@@ -26,6 +25,5 @@ module Sidekiq
|
|
26
25
|
end
|
27
26
|
end
|
28
27
|
end
|
29
|
-
|
30
28
|
end
|
31
29
|
end
|
@@ -3,6 +3,8 @@ require 'yaml'
|
|
3
3
|
|
4
4
|
module Sidekiq
|
5
5
|
module Extensions
|
6
|
+
SIZE_LIMIT = 8_192
|
7
|
+
|
6
8
|
class Proxy < BasicObject
|
7
9
|
def initialize(performable, target, options={})
|
8
10
|
@performable = performable
|
@@ -17,7 +19,11 @@ module Sidekiq
|
|
17
19
|
# to JSON and then deserialized on the other side back into a
|
18
20
|
# Ruby object.
|
19
21
|
obj = [@target, name, args]
|
20
|
-
|
22
|
+
marshalled = ::YAML.dump(obj)
|
23
|
+
if marshalled.size > SIZE_LIMIT
|
24
|
+
::Sidekiq.logger.warn { "#{@target}.#{name} job argument is #{marshalled.bytesize} bytes, you should refactor it to reduce the size" }
|
25
|
+
end
|
26
|
+
@performable.client_push({ 'class' => @performable, 'args' => [marshalled] }.merge(@opts))
|
21
27
|
end
|
22
28
|
end
|
23
29
|
|
data/lib/sidekiq/fetch.rb
CHANGED
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Sidekiq
|
3
|
+
class JobLogger
|
4
|
+
|
5
|
+
def call(item, queue)
|
6
|
+
start = Time.now
|
7
|
+
logger.info("start")
|
8
|
+
yield
|
9
|
+
logger.info("done: #{elapsed(start)} sec")
|
10
|
+
rescue Exception
|
11
|
+
logger.info("fail: #{elapsed(start)} sec")
|
12
|
+
raise
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def elapsed(start)
|
18
|
+
(Time.now - start).round(3)
|
19
|
+
end
|
20
|
+
|
21
|
+
def logger
|
22
|
+
Sidekiq.logger
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|