sidekiq 6.0.0 → 6.0.2
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/.circleci/config.yml +21 -0
- data/6.0-Upgrade.md +3 -1
- data/Changes.md +82 -1
- data/Ent-Changes.md +6 -0
- data/Gemfile.lock +3 -3
- data/Pro-Changes.md +9 -1
- data/README.md +3 -1
- data/bin/sidekiqload +8 -4
- data/bin/sidekiqmon +4 -5
- data/lib/generators/sidekiq/worker_generator.rb +10 -0
- data/lib/sidekiq/api.rb +104 -63
- data/lib/sidekiq/cli.rb +18 -16
- data/lib/sidekiq/client.rb +8 -2
- data/lib/sidekiq/fetch.rb +7 -7
- data/lib/sidekiq/job_logger.rb +11 -3
- data/lib/sidekiq/job_retry.rb +21 -8
- data/lib/sidekiq/launcher.rb +1 -3
- data/lib/sidekiq/logger.rb +107 -11
- data/lib/sidekiq/middleware/chain.rb +11 -2
- data/lib/sidekiq/monitor.rb +1 -16
- data/lib/sidekiq/paginator.rb +7 -2
- data/lib/sidekiq/processor.rb +17 -19
- data/lib/sidekiq/scheduled.rb +13 -12
- data/lib/sidekiq/testing.rb +12 -0
- data/lib/sidekiq/util.rb +0 -2
- data/lib/sidekiq/version.rb +1 -1
- data/lib/sidekiq/web/application.rb +8 -13
- data/lib/sidekiq/web/helpers.rb +22 -10
- data/lib/sidekiq/worker.rb +4 -4
- data/lib/sidekiq.rb +8 -0
- data/sidekiq.gemspec +1 -1
- data/web/assets/javascripts/dashboard.js +2 -2
- data/web/assets/stylesheets/application-dark.css +125 -0
- data/web/assets/stylesheets/application.css +9 -0
- data/web/locales/de.yml +14 -2
- data/web/views/_job_info.erb +2 -1
- data/web/views/busy.erb +4 -1
- data/web/views/dead.erb +2 -2
- data/web/views/layout.erb +1 -0
- data/web/views/morgue.erb +4 -1
- data/web/views/queue.erb +10 -1
- data/web/views/retries.erb +4 -1
- data/web/views/retry.erb +2 -2
- data/web/views/scheduled.erb +4 -1
- metadata +5 -4
data/lib/sidekiq/cli.rb
CHANGED
@@ -41,9 +41,11 @@ module Sidekiq
|
|
41
41
|
|
42
42
|
self_read, self_write = IO.pipe
|
43
43
|
sigs = %w[INT TERM TTIN TSTP]
|
44
|
+
# USR1 and USR2 don't work on the JVM
|
45
|
+
sigs << "USR2" unless jruby?
|
44
46
|
sigs.each do |sig|
|
45
47
|
trap sig do
|
46
|
-
self_write.
|
48
|
+
self_write.puts(sig)
|
47
49
|
end
|
48
50
|
rescue ArgumentError
|
49
51
|
puts "Signal #{sig} not supported"
|
@@ -162,15 +164,12 @@ module Sidekiq
|
|
162
164
|
end
|
163
165
|
},
|
164
166
|
}
|
167
|
+
UNHANDLED_SIGNAL_HANDLER = ->(cli) { Sidekiq.logger.info "No signal handler registered, ignoring" }
|
168
|
+
SIGNAL_HANDLERS.default = UNHANDLED_SIGNAL_HANDLER
|
165
169
|
|
166
170
|
def handle_signal(sig)
|
167
171
|
Sidekiq.logger.debug "Got #{sig} signal"
|
168
|
-
|
169
|
-
if handy
|
170
|
-
handy.call(self)
|
171
|
-
else
|
172
|
-
Sidekiq.logger.info { "No signal handler for #{sig}" }
|
173
|
-
end
|
172
|
+
SIGNAL_HANDLERS[sig].call(self)
|
174
173
|
end
|
175
174
|
|
176
175
|
private
|
@@ -204,7 +203,7 @@ module Sidekiq
|
|
204
203
|
|
205
204
|
# check config file presence
|
206
205
|
if opts[:config_file]
|
207
|
-
|
206
|
+
unless File.exist?(opts[:config_file])
|
208
207
|
raise ArgumentError, "No such file #{opts[:config_file]}"
|
209
208
|
end
|
210
209
|
else
|
@@ -224,7 +223,7 @@ module Sidekiq
|
|
224
223
|
opts = parse_config(opts[:config_file]).merge(opts) if opts[:config_file]
|
225
224
|
|
226
225
|
# set defaults
|
227
|
-
opts[:queues] =
|
226
|
+
opts[:queues] = ["default"] if opts[:queues].nil? || opts[:queues].empty?
|
228
227
|
opts[:strict] = true if opts[:strict].nil?
|
229
228
|
opts[:concurrency] = Integer(ENV["RAILS_MAX_THREADS"]) if opts[:concurrency].nil? && ENV["RAILS_MAX_THREADS"]
|
230
229
|
|
@@ -283,8 +282,13 @@ module Sidekiq
|
|
283
282
|
|
284
283
|
def parse_options(argv)
|
285
284
|
opts = {}
|
285
|
+
@parser = option_parser(opts)
|
286
|
+
@parser.parse!(argv)
|
287
|
+
opts
|
288
|
+
end
|
286
289
|
|
287
|
-
|
290
|
+
def option_parser(opts)
|
291
|
+
parser = OptionParser.new { |o|
|
288
292
|
o.on "-c", "--concurrency INT", "processor threads to use" do |arg|
|
289
293
|
opts[:concurrency] = Integer(arg)
|
290
294
|
end
|
@@ -336,15 +340,13 @@ module Sidekiq
|
|
336
340
|
end
|
337
341
|
}
|
338
342
|
|
339
|
-
|
340
|
-
|
341
|
-
logger.info
|
343
|
+
parser.banner = "sidekiq [options]"
|
344
|
+
parser.on_tail "-h", "--help", "Show help" do
|
345
|
+
logger.info parser
|
342
346
|
die 1
|
343
347
|
end
|
344
348
|
|
345
|
-
|
346
|
-
|
347
|
-
opts
|
349
|
+
parser
|
348
350
|
end
|
349
351
|
|
350
352
|
def initialize_logger
|
data/lib/sidekiq/client.rb
CHANGED
@@ -94,9 +94,14 @@ module Sidekiq
|
|
94
94
|
return [] unless arg # no jobs to push
|
95
95
|
raise ArgumentError, "Bulk arguments must be an Array of Arrays: [[1], [2]]" unless arg.is_a?(Array)
|
96
96
|
|
97
|
+
at = items.delete("at")
|
98
|
+
raise ArgumentError, "Job 'at' must be a Numeric or an Array of Numeric timestamps" if at && (Array(at).empty? || !Array(at).all?(Numeric))
|
99
|
+
|
97
100
|
normed = normalize_item(items)
|
98
|
-
payloads = items["args"].map { |args|
|
99
|
-
|
101
|
+
payloads = items["args"].map.with_index { |args, index|
|
102
|
+
single_at = at.is_a?(Array) ? at[index] : at
|
103
|
+
copy = normed.merge("args" => args, "jid" => SecureRandom.hex(12), "at" => single_at, "enqueued_at" => Time.now.to_f)
|
104
|
+
|
100
105
|
result = process_single(items["class"], copy)
|
101
106
|
result || nil
|
102
107
|
}.compact
|
@@ -218,6 +223,7 @@ module Sidekiq
|
|
218
223
|
raise(ArgumentError, "Job args must be an Array") unless item["args"].is_a?(Array)
|
219
224
|
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)
|
220
225
|
raise(ArgumentError, "Job 'at' must be a Numeric timestamp") if item.key?("at") && !item["at"].is_a?(Numeric)
|
226
|
+
raise(ArgumentError, "Job tags must be an Array") if item["tags"] && !item["tags"].is_a?(Array)
|
221
227
|
# 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']
|
222
228
|
|
223
229
|
normalized_hash(item["class"])
|
data/lib/sidekiq/fetch.rb
CHANGED
@@ -14,12 +14,12 @@ module Sidekiq
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def queue_name
|
17
|
-
queue.
|
17
|
+
queue.delete_prefix("queue:")
|
18
18
|
end
|
19
19
|
|
20
20
|
def requeue
|
21
21
|
Sidekiq.redis do |conn|
|
22
|
-
conn.rpush(
|
22
|
+
conn.rpush(queue, job)
|
23
23
|
end
|
24
24
|
end
|
25
25
|
}
|
@@ -28,7 +28,7 @@ module Sidekiq
|
|
28
28
|
@strictly_ordered_queues = !!options[:strict]
|
29
29
|
@queues = options[:queues].map { |q| "queue:#{q}" }
|
30
30
|
if @strictly_ordered_queues
|
31
|
-
@queues
|
31
|
+
@queues.uniq!
|
32
32
|
@queues << TIMEOUT
|
33
33
|
end
|
34
34
|
end
|
@@ -47,7 +47,7 @@ module Sidekiq
|
|
47
47
|
if @strictly_ordered_queues
|
48
48
|
@queues
|
49
49
|
else
|
50
|
-
queues = @queues.shuffle
|
50
|
+
queues = @queues.shuffle!.uniq
|
51
51
|
queues << TIMEOUT
|
52
52
|
queues
|
53
53
|
end
|
@@ -61,14 +61,14 @@ module Sidekiq
|
|
61
61
|
Sidekiq.logger.debug { "Re-queueing terminated jobs" }
|
62
62
|
jobs_to_requeue = {}
|
63
63
|
inprogress.each do |unit_of_work|
|
64
|
-
jobs_to_requeue[unit_of_work.
|
65
|
-
jobs_to_requeue[unit_of_work.
|
64
|
+
jobs_to_requeue[unit_of_work.queue] ||= []
|
65
|
+
jobs_to_requeue[unit_of_work.queue] << unit_of_work.job
|
66
66
|
end
|
67
67
|
|
68
68
|
Sidekiq.redis do |conn|
|
69
69
|
conn.pipelined do
|
70
70
|
jobs_to_requeue.each do |queue, jobs|
|
71
|
-
conn.rpush(
|
71
|
+
conn.rpush(queue, jobs)
|
72
72
|
end
|
73
73
|
end
|
74
74
|
end
|
data/lib/sidekiq/job_logger.rb
CHANGED
@@ -23,8 +23,15 @@ module Sidekiq
|
|
23
23
|
raise
|
24
24
|
end
|
25
25
|
|
26
|
-
def
|
27
|
-
|
26
|
+
def prepare(job_hash, &block)
|
27
|
+
level = job_hash["log_level"]
|
28
|
+
if level
|
29
|
+
@logger.log_at(level) do
|
30
|
+
Sidekiq::Context.with(job_hash_context(job_hash), &block)
|
31
|
+
end
|
32
|
+
else
|
33
|
+
Sidekiq::Context.with(job_hash_context(job_hash), &block)
|
34
|
+
end
|
28
35
|
end
|
29
36
|
|
30
37
|
def job_hash_context(job_hash)
|
@@ -35,11 +42,12 @@ module Sidekiq
|
|
35
42
|
jid: job_hash["jid"],
|
36
43
|
}
|
37
44
|
h[:bid] = job_hash["bid"] if job_hash["bid"]
|
45
|
+
h[:tags] = job_hash["tags"] if job_hash["tags"]
|
38
46
|
h
|
39
47
|
end
|
40
48
|
|
41
49
|
def with_elapsed_time_context(start, &block)
|
42
|
-
|
50
|
+
Sidekiq::Context.with(elapsed_time_context(start), &block)
|
43
51
|
end
|
44
52
|
|
45
53
|
def elapsed_time_context(start)
|
data/lib/sidekiq/job_retry.rb
CHANGED
@@ -3,6 +3,9 @@
|
|
3
3
|
require "sidekiq/scheduled"
|
4
4
|
require "sidekiq/api"
|
5
5
|
|
6
|
+
require "zlib"
|
7
|
+
require "base64"
|
8
|
+
|
6
9
|
module Sidekiq
|
7
10
|
##
|
8
11
|
# Automatically retry jobs that fail in Sidekiq.
|
@@ -71,7 +74,7 @@ module Sidekiq
|
|
71
74
|
# The global retry handler requires only the barest of data.
|
72
75
|
# We want to be able to retry as much as possible so we don't
|
73
76
|
# require the worker to be instantiated.
|
74
|
-
def global(
|
77
|
+
def global(jobstr, queue)
|
75
78
|
yield
|
76
79
|
rescue Handled => ex
|
77
80
|
raise ex
|
@@ -82,6 +85,7 @@ module Sidekiq
|
|
82
85
|
# ignore, will be pushed back onto queue during hard_shutdown
|
83
86
|
raise Sidekiq::Shutdown if exception_caused_by_shutdown?(e)
|
84
87
|
|
88
|
+
msg = Sidekiq.load_json(jobstr)
|
85
89
|
if msg["retry"]
|
86
90
|
attempt_retry(nil, msg, queue, e)
|
87
91
|
else
|
@@ -103,7 +107,7 @@ module Sidekiq
|
|
103
107
|
# exception so the global block does not reprocess the error. The
|
104
108
|
# Skip exception is unwrapped within Sidekiq::Processor#process before
|
105
109
|
# calling the handle_exception handlers.
|
106
|
-
def local(worker,
|
110
|
+
def local(worker, jobstr, queue)
|
107
111
|
yield
|
108
112
|
rescue Handled => ex
|
109
113
|
raise ex
|
@@ -114,6 +118,7 @@ module Sidekiq
|
|
114
118
|
# ignore, will be pushed back onto queue during hard_shutdown
|
115
119
|
raise Sidekiq::Shutdown if exception_caused_by_shutdown?(e)
|
116
120
|
|
121
|
+
msg = Sidekiq.load_json(jobstr)
|
117
122
|
if msg["retry"].nil?
|
118
123
|
msg["retry"] = worker.class.get_sidekiq_options["retry"]
|
119
124
|
end
|
@@ -151,12 +156,14 @@ module Sidekiq
|
|
151
156
|
msg["retry_count"] = 0
|
152
157
|
end
|
153
158
|
|
154
|
-
if msg["backtrace"]
|
155
|
-
msg["
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
159
|
+
if msg["backtrace"]
|
160
|
+
lines = if msg["backtrace"] == true
|
161
|
+
exception.backtrace
|
162
|
+
else
|
163
|
+
exception.backtrace[0...msg["backtrace"].to_i]
|
164
|
+
end
|
165
|
+
|
166
|
+
msg["error_backtrace"] = compress_backtrace(lines)
|
160
167
|
end
|
161
168
|
|
162
169
|
if count < max_retry_attempts
|
@@ -245,5 +252,11 @@ module Sidekiq
|
|
245
252
|
rescue
|
246
253
|
+"!!! ERROR MESSAGE THREW AN ERROR !!!"
|
247
254
|
end
|
255
|
+
|
256
|
+
def compress_backtrace(backtrace)
|
257
|
+
serialized = Sidekiq.dump_json(backtrace)
|
258
|
+
compressed = Zlib::Deflate.deflate(serialized)
|
259
|
+
Base64.encode64(compressed)
|
260
|
+
end
|
248
261
|
end
|
249
262
|
end
|
data/lib/sidekiq/launcher.rb
CHANGED
@@ -129,15 +129,13 @@ module Sidekiq
|
|
129
129
|
fails = procd = 0
|
130
130
|
|
131
131
|
_, exists, _, _, msg = Sidekiq.redis { |conn|
|
132
|
-
|
132
|
+
conn.multi {
|
133
133
|
conn.sadd("processes", key)
|
134
134
|
conn.exists(key)
|
135
135
|
conn.hmset(key, "info", to_json, "busy", curstate.size, "beat", Time.now.to_f, "quiet", @done)
|
136
136
|
conn.expire(key, 60)
|
137
137
|
conn.rpop("#{key}-signals")
|
138
138
|
}
|
139
|
-
|
140
|
-
res
|
141
139
|
}
|
142
140
|
|
143
141
|
# first heartbeat or recovering from an outage and need to reestablish our heartbeat
|
data/lib/sidekiq/logger.rb
CHANGED
@@ -4,22 +4,109 @@ require "logger"
|
|
4
4
|
require "time"
|
5
5
|
|
6
6
|
module Sidekiq
|
7
|
-
|
8
|
-
def
|
9
|
-
|
7
|
+
module Context
|
8
|
+
def self.with(hash)
|
9
|
+
current.merge!(hash)
|
10
|
+
yield
|
11
|
+
ensure
|
12
|
+
hash.each_key { |key| current.delete(key) }
|
13
|
+
end
|
10
14
|
|
11
|
-
|
15
|
+
def self.current
|
16
|
+
Thread.current[:sidekiq_context] ||= {}
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
module LoggingUtils
|
21
|
+
LEVELS = {
|
22
|
+
"debug" => 0,
|
23
|
+
"info" => 1,
|
24
|
+
"warn" => 2,
|
25
|
+
"error" => 3,
|
26
|
+
"fatal" => 4,
|
27
|
+
}
|
28
|
+
LEVELS.default_proc = proc do |_, level|
|
29
|
+
Sidekiq.logger.warn("Invalid log level: #{level.inspect}")
|
30
|
+
nil
|
31
|
+
end
|
32
|
+
|
33
|
+
def debug?
|
34
|
+
level >= 0
|
35
|
+
end
|
36
|
+
|
37
|
+
def info?
|
38
|
+
level >= 1
|
39
|
+
end
|
40
|
+
|
41
|
+
def warn?
|
42
|
+
level >= 2
|
43
|
+
end
|
44
|
+
|
45
|
+
def error?
|
46
|
+
level >= 3
|
47
|
+
end
|
48
|
+
|
49
|
+
def fatal?
|
50
|
+
level >= 4
|
12
51
|
end
|
13
52
|
|
14
|
-
def
|
15
|
-
|
53
|
+
def local_level
|
54
|
+
Thread.current[:sidekiq_log_level]
|
55
|
+
end
|
56
|
+
|
57
|
+
def local_level=(level)
|
58
|
+
case level
|
59
|
+
when Integer
|
60
|
+
Thread.current[:sidekiq_log_level] = level
|
61
|
+
when Symbol, String
|
62
|
+
Thread.current[:sidekiq_log_level] = LEVELS[level.to_s]
|
63
|
+
when nil
|
64
|
+
Thread.current[:sidekiq_log_level] = nil
|
65
|
+
else
|
66
|
+
raise ArgumentError, "Invalid log level: #{level.inspect}"
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def level
|
71
|
+
local_level || super
|
72
|
+
end
|
73
|
+
|
74
|
+
# Change the thread-local level for the duration of the given block.
|
75
|
+
def log_at(level)
|
76
|
+
old_local_level = local_level
|
77
|
+
self.local_level = level
|
16
78
|
yield
|
17
79
|
ensure
|
18
|
-
|
80
|
+
self.local_level = old_local_level
|
19
81
|
end
|
20
82
|
|
21
|
-
|
22
|
-
|
83
|
+
# Redefined to check severity against #level, and thus the thread-local level, rather than +@level+.
|
84
|
+
# FIXME: Remove when the minimum Ruby version supports overriding Logger#level.
|
85
|
+
def add(severity, message = nil, progname = nil, &block)
|
86
|
+
severity ||= UNKNOWN
|
87
|
+
progname ||= @progname
|
88
|
+
|
89
|
+
return true if @logdev.nil? || severity < level
|
90
|
+
|
91
|
+
if message.nil?
|
92
|
+
if block_given?
|
93
|
+
message = yield
|
94
|
+
else
|
95
|
+
message = progname
|
96
|
+
progname = @progname
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
@logdev.write format_message(format_severity(severity), Time.now, progname, message)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
class Logger < ::Logger
|
105
|
+
include LoggingUtils
|
106
|
+
|
107
|
+
def initialize(*args)
|
108
|
+
super
|
109
|
+
self.formatter = Sidekiq.log_formatter
|
23
110
|
end
|
24
111
|
|
25
112
|
module Formatters
|
@@ -29,11 +116,20 @@ module Sidekiq
|
|
29
116
|
end
|
30
117
|
|
31
118
|
def ctx
|
32
|
-
|
119
|
+
Sidekiq::Context.current
|
33
120
|
end
|
34
121
|
|
35
122
|
def format_context
|
36
|
-
|
123
|
+
if ctx.any?
|
124
|
+
" " + ctx.compact.map { |k, v|
|
125
|
+
case v
|
126
|
+
when Array
|
127
|
+
"#{k}=#{v.join(",")}"
|
128
|
+
else
|
129
|
+
"#{k}=#{v}"
|
130
|
+
end
|
131
|
+
}.join(" ")
|
132
|
+
end
|
37
133
|
end
|
38
134
|
end
|
39
135
|
|
@@ -67,7 +67,6 @@ module Sidekiq
|
|
67
67
|
module Middleware
|
68
68
|
class Chain
|
69
69
|
include Enumerable
|
70
|
-
attr_reader :entries
|
71
70
|
|
72
71
|
def initialize_copy(copy)
|
73
72
|
copy.instance_variable_set(:@entries, entries.dup)
|
@@ -78,10 +77,14 @@ module Sidekiq
|
|
78
77
|
end
|
79
78
|
|
80
79
|
def initialize
|
81
|
-
@entries =
|
80
|
+
@entries = nil
|
82
81
|
yield self if block_given?
|
83
82
|
end
|
84
83
|
|
84
|
+
def entries
|
85
|
+
@entries ||= []
|
86
|
+
end
|
87
|
+
|
85
88
|
def remove(klass)
|
86
89
|
entries.delete_if { |entry| entry.klass == klass }
|
87
90
|
end
|
@@ -114,6 +117,10 @@ module Sidekiq
|
|
114
117
|
any? { |entry| entry.klass == klass }
|
115
118
|
end
|
116
119
|
|
120
|
+
def empty?
|
121
|
+
@entries.nil? || @entries.empty?
|
122
|
+
end
|
123
|
+
|
117
124
|
def retrieve
|
118
125
|
map(&:make_new)
|
119
126
|
end
|
@@ -123,6 +130,8 @@ module Sidekiq
|
|
123
130
|
end
|
124
131
|
|
125
132
|
def invoke(*args)
|
133
|
+
return yield if empty?
|
134
|
+
|
126
135
|
chain = retrieve.dup
|
127
136
|
traverse_chain = lambda do
|
128
137
|
if chain.empty?
|
data/lib/sidekiq/monitor.rb
CHANGED
@@ -4,21 +4,6 @@ require "fileutils"
|
|
4
4
|
require "sidekiq/api"
|
5
5
|
|
6
6
|
class Sidekiq::Monitor
|
7
|
-
CMD = File.basename($PROGRAM_NAME)
|
8
|
-
|
9
|
-
attr_reader :stage
|
10
|
-
|
11
|
-
def self.print_usage
|
12
|
-
puts "#{CMD} - monitor Sidekiq from the command line."
|
13
|
-
puts
|
14
|
-
puts "Usage: #{CMD} status <section>"
|
15
|
-
puts
|
16
|
-
puts " <section> (optional) view a specific section of the status output"
|
17
|
-
puts " Valid sections are: #{Sidekiq::Monitor::Status::VALID_SECTIONS.join(", ")}"
|
18
|
-
puts
|
19
|
-
puts "Set REDIS_URL to the location of your Redis server if not monitoring localhost."
|
20
|
-
end
|
21
|
-
|
22
7
|
class Status
|
23
8
|
VALID_SECTIONS = %w[all version overview processes queues]
|
24
9
|
COL_PAD = 2
|
@@ -47,7 +32,7 @@ class Sidekiq::Monitor
|
|
47
32
|
|
48
33
|
def version
|
49
34
|
puts "Sidekiq #{Sidekiq::VERSION}"
|
50
|
-
puts Time.now
|
35
|
+
puts Time.now.utc
|
51
36
|
end
|
52
37
|
|
53
38
|
def overview
|
data/lib/sidekiq/paginator.rb
CHANGED
@@ -12,10 +12,10 @@ module Sidekiq
|
|
12
12
|
|
13
13
|
Sidekiq.redis do |conn|
|
14
14
|
type = conn.type(key)
|
15
|
+
rev = opts && opts[:reverse]
|
15
16
|
|
16
17
|
case type
|
17
18
|
when "zset"
|
18
|
-
rev = opts && opts[:reverse]
|
19
19
|
total_size, items = conn.multi {
|
20
20
|
conn.zcard(key)
|
21
21
|
if rev
|
@@ -28,8 +28,13 @@ module Sidekiq
|
|
28
28
|
when "list"
|
29
29
|
total_size, items = conn.multi {
|
30
30
|
conn.llen(key)
|
31
|
-
|
31
|
+
if rev
|
32
|
+
conn.lrange(key, -ending - 1, -starting - 1)
|
33
|
+
else
|
34
|
+
conn.lrange(key, starting, ending)
|
35
|
+
end
|
32
36
|
}
|
37
|
+
items.reverse! if rev
|
33
38
|
[current_page, total_size, items]
|
34
39
|
when "none"
|
35
40
|
[1, 0, []]
|
data/lib/sidekiq/processor.rb
CHANGED
@@ -111,16 +111,19 @@ module Sidekiq
|
|
111
111
|
nil
|
112
112
|
end
|
113
113
|
|
114
|
-
def dispatch(job_hash, queue)
|
114
|
+
def dispatch(job_hash, queue, jobstr)
|
115
115
|
# since middleware can mutate the job hash
|
116
|
-
# we clone
|
116
|
+
# we need to clone it to report the original
|
117
117
|
# job structure to the Web UI
|
118
|
-
|
118
|
+
# or to push back to redis when retrying.
|
119
|
+
# To avoid costly and, most of the time, useless cloning here,
|
120
|
+
# we pass original String of JSON to respected methods
|
121
|
+
# to re-parse it there if we need access to the original, untouched job
|
119
122
|
|
120
|
-
@job_logger.
|
121
|
-
@retrier.global(
|
123
|
+
@job_logger.prepare(job_hash) do
|
124
|
+
@retrier.global(jobstr, queue) do
|
122
125
|
@job_logger.call(job_hash, queue) do
|
123
|
-
stats(
|
126
|
+
stats(jobstr, queue) do
|
124
127
|
# Rails 5 requires a Reloader to wrap code execution. In order to
|
125
128
|
# constantize the worker and instantiate an instance, we have to call
|
126
129
|
# the Reloader. It handles code loading, db connection management, etc.
|
@@ -129,7 +132,7 @@ module Sidekiq
|
|
129
132
|
klass = constantize(job_hash["class"])
|
130
133
|
worker = klass.new
|
131
134
|
worker.jid = job_hash["jid"]
|
132
|
-
@retrier.local(worker,
|
135
|
+
@retrier.local(worker, jobstr, queue) do
|
133
136
|
yield worker
|
134
137
|
end
|
135
138
|
end
|
@@ -156,9 +159,9 @@ module Sidekiq
|
|
156
159
|
|
157
160
|
ack = false
|
158
161
|
begin
|
159
|
-
dispatch(job_hash, queue) do |worker|
|
162
|
+
dispatch(job_hash, queue, jobstr) do |worker|
|
160
163
|
Sidekiq.server_middleware.invoke(worker, job_hash, queue) do
|
161
|
-
execute_job(worker,
|
164
|
+
execute_job(worker, job_hash["args"])
|
162
165
|
end
|
163
166
|
end
|
164
167
|
ack = true
|
@@ -247,8 +250,8 @@ module Sidekiq
|
|
247
250
|
FAILURE = Counter.new
|
248
251
|
WORKER_STATE = SharedWorkerState.new
|
249
252
|
|
250
|
-
def stats(
|
251
|
-
WORKER_STATE.set(tid, {queue: queue, payload:
|
253
|
+
def stats(jobstr, queue)
|
254
|
+
WORKER_STATE.set(tid, {queue: queue, payload: jobstr, run_at: Time.now.to_i})
|
252
255
|
|
253
256
|
begin
|
254
257
|
yield
|
@@ -261,21 +264,16 @@ module Sidekiq
|
|
261
264
|
end
|
262
265
|
end
|
263
266
|
|
264
|
-
# Deep clone the arguments passed to the worker so that if
|
265
|
-
# the job fails, what is pushed back onto Redis hasn't
|
266
|
-
# been mutated by the worker.
|
267
|
-
def cloned(thing)
|
268
|
-
Marshal.load(Marshal.dump(thing))
|
269
|
-
end
|
270
|
-
|
271
267
|
def constantize(str)
|
268
|
+
return Object.const_get(str) unless str.include?("::")
|
269
|
+
|
272
270
|
names = str.split("::")
|
273
271
|
names.shift if names.empty? || names.first.empty?
|
274
272
|
|
275
273
|
names.inject(Object) do |constant, name|
|
276
274
|
# the false flag limits search for name to under the constant namespace
|
277
275
|
# which mimics Rails' behaviour
|
278
|
-
constant.
|
276
|
+
constant.const_get(name, false)
|
279
277
|
end
|
280
278
|
end
|
281
279
|
end
|
data/lib/sidekiq/scheduled.rb
CHANGED
@@ -14,18 +14,19 @@ module Sidekiq
|
|
14
14
|
# Just check Redis for the set of jobs with a timestamp before now.
|
15
15
|
Sidekiq.redis do |conn|
|
16
16
|
sorted_sets.each do |sorted_set|
|
17
|
-
# Get
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
17
|
+
# Get next items in the queue with scores (time to execute) <= now.
|
18
|
+
until (jobs = conn.zrangebyscore(sorted_set, "-inf", now, limit: [0, 100])).empty?
|
19
|
+
# We need to go through the list one at a time to reduce the risk of something
|
20
|
+
# going wrong between the time jobs are popped from the scheduled queue and when
|
21
|
+
# they are pushed onto a work queue and losing the jobs.
|
22
|
+
jobs.each do |job|
|
23
|
+
# Pop item off the queue and add it to the work queue. If the job can't be popped from
|
24
|
+
# the queue, it's because another process already popped it so we can move on to the
|
25
|
+
# next one.
|
26
|
+
if conn.zrem(sorted_set, job)
|
27
|
+
Sidekiq::Client.push(Sidekiq.load_json(job))
|
28
|
+
Sidekiq.logger.debug { "enqueued #{sorted_set}: #{job}" }
|
29
|
+
end
|
29
30
|
end
|
30
31
|
end
|
31
32
|
end
|
data/lib/sidekiq/testing.rb
CHANGED
@@ -323,6 +323,18 @@ module Sidekiq
|
|
323
323
|
end
|
324
324
|
end
|
325
325
|
end
|
326
|
+
|
327
|
+
module TestingExtensions
|
328
|
+
def jobs_for(klass)
|
329
|
+
jobs.select do |job|
|
330
|
+
marshalled = job["args"][0]
|
331
|
+
marshalled.index(klass.to_s) && YAML.load(marshalled)[0] == klass
|
332
|
+
end
|
333
|
+
end
|
334
|
+
end
|
335
|
+
|
336
|
+
Sidekiq::Extensions::DelayedMailer.extend(TestingExtensions) if defined?(Sidekiq::Extensions::DelayedMailer)
|
337
|
+
Sidekiq::Extensions::DelayedModel.extend(TestingExtensions) if defined?(Sidekiq::Extensions::DelayedModel)
|
326
338
|
end
|
327
339
|
|
328
340
|
if defined?(::Rails) && Rails.respond_to?(:env) && !Rails.env.test?
|
data/lib/sidekiq/util.rb
CHANGED
data/lib/sidekiq/version.rb
CHANGED