sidekiq 2.17.8 → 3.0.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/3.0-Upgrade.md +63 -0
- data/Changes.md +66 -3
- data/Contributing.md +1 -3
- data/Pro-Changes.md +18 -0
- data/README.md +2 -2
- data/bin/sidekiqctl +19 -6
- data/lib/sidekiq.rb +53 -11
- data/lib/sidekiq/actor.rb +1 -0
- data/lib/sidekiq/api.rb +145 -58
- data/lib/sidekiq/cli.rb +22 -18
- data/lib/sidekiq/client.rb +44 -14
- data/lib/sidekiq/core_ext.rb +5 -8
- data/lib/sidekiq/exception_handler.rb +19 -28
- data/lib/sidekiq/fetch.rb +3 -3
- data/lib/sidekiq/launcher.rb +30 -3
- data/lib/sidekiq/logging.rb +2 -2
- data/lib/sidekiq/manager.rb +19 -16
- data/lib/sidekiq/middleware/chain.rb +1 -1
- data/lib/sidekiq/middleware/i18n.rb +1 -1
- data/lib/sidekiq/middleware/server/retry_jobs.rb +23 -7
- data/lib/sidekiq/processor.rb +36 -54
- data/lib/sidekiq/redis_connection.rb +1 -3
- data/lib/sidekiq/util.rb +4 -4
- data/lib/sidekiq/version.rb +1 -1
- data/lib/sidekiq/web.rb +57 -8
- data/lib/sidekiq/web_helpers.rb +6 -15
- data/lib/sidekiq/worker.rb +3 -1
- data/sidekiq.gemspec +5 -5
- data/test/test_api.rb +59 -19
- data/test/test_cli.rb +1 -1
- data/test/test_client.rb +44 -5
- data/test/test_exception_handler.rb +4 -87
- data/test/test_middleware.rb +3 -2
- data/test/test_redis_connection.rb +0 -6
- data/test/test_retry.rb +13 -68
- data/test/test_scheduled.rb +1 -1
- data/test/test_scheduling.rb +5 -0
- data/test/test_sidekiq.rb +18 -0
- data/test/test_web.rb +98 -58
- data/web/assets/stylesheets/application.css +5 -0
- data/web/locales/cs.yml +68 -0
- data/web/locales/da.yml +9 -1
- data/web/locales/de.yml +15 -7
- data/web/locales/el.yml +68 -0
- data/web/locales/en.yml +8 -3
- data/web/locales/es.yml +9 -1
- data/web/locales/fr.yml +34 -26
- data/web/locales/it.yml +26 -18
- data/web/locales/ja.yml +8 -2
- data/web/locales/ko.yml +0 -2
- data/web/locales/nl.yml +8 -3
- data/web/locales/no.yml +9 -3
- data/web/locales/pl.yml +0 -1
- data/web/locales/pt-br.yml +11 -4
- data/web/locales/pt.yml +8 -1
- data/web/locales/ru.yml +29 -22
- data/web/locales/sv.yml +68 -0
- data/web/locales/zh-tw.yml +68 -0
- data/web/views/_job_info.erb +8 -2
- data/web/views/_summary.erb +13 -7
- data/web/views/busy.erb +55 -0
- data/web/views/dead.erb +30 -0
- data/web/views/layout.erb +1 -0
- data/web/views/morgue.erb +66 -0
- metadata +29 -30
- data/config.ru +0 -18
- data/lib/sidekiq/capistrano.rb +0 -5
- data/lib/sidekiq/capistrano2.rb +0 -54
- data/lib/sidekiq/tasks/sidekiq.rake +0 -119
- data/lib/sidekiq/yaml_patch.rb +0 -21
- data/test/test_util.rb +0 -18
- data/web/views/_workers.erb +0 -22
- data/web/views/workers.erb +0 -16
data/lib/sidekiq/cli.rb
CHANGED
@@ -43,6 +43,13 @@ module Sidekiq
|
|
43
43
|
end
|
44
44
|
|
45
45
|
def run
|
46
|
+
# Print logo and banner for development
|
47
|
+
if environment == 'development' && $stdout.tty?
|
48
|
+
puts "\e[#{31}m"
|
49
|
+
puts Sidekiq::BANNER
|
50
|
+
puts "\e[0m"
|
51
|
+
end
|
52
|
+
|
46
53
|
self_read, self_write = IO.pipe
|
47
54
|
|
48
55
|
%w(INT TERM USR1 USR2 TTIN).each do |sig|
|
@@ -55,23 +62,19 @@ module Sidekiq
|
|
55
62
|
end
|
56
63
|
end
|
57
64
|
|
58
|
-
redis {} # noop to connect redis and print info
|
59
65
|
logger.info "Running in #{RUBY_DESCRIPTION}"
|
60
66
|
logger.info Sidekiq::LICENSE
|
61
67
|
|
68
|
+
fire_event(:startup)
|
69
|
+
|
62
70
|
if !options[:daemon]
|
63
71
|
logger.info 'Starting processing, hit Ctrl-C to stop'
|
64
72
|
end
|
65
73
|
|
66
74
|
require 'sidekiq/launcher'
|
67
75
|
@launcher = Sidekiq::Launcher.new(options)
|
68
|
-
launcher.procline(options[:tag] ? "#{options[:tag]} " : '')
|
69
76
|
|
70
77
|
begin
|
71
|
-
if options[:profile]
|
72
|
-
require 'ruby-prof'
|
73
|
-
RubyProf.start
|
74
|
-
end
|
75
78
|
launcher.run
|
76
79
|
|
77
80
|
while readable_io = IO.select([self_read])
|
@@ -81,6 +84,7 @@ module Sidekiq
|
|
81
84
|
rescue Interrupt
|
82
85
|
logger.info 'Shutting down'
|
83
86
|
launcher.stop
|
87
|
+
fire_event(:shutdown)
|
84
88
|
# Explicitly exit so busy Processor threads can't block
|
85
89
|
# process shutdown.
|
86
90
|
exit(0)
|
@@ -89,17 +93,20 @@ module Sidekiq
|
|
89
93
|
|
90
94
|
private
|
91
95
|
|
96
|
+
def fire_event(event)
|
97
|
+
Sidekiq.options[:lifecycle_events][event].each do |block|
|
98
|
+
begin
|
99
|
+
block.call
|
100
|
+
rescue => ex
|
101
|
+
handle_exception(ex, { :event => event })
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
92
106
|
def handle_signal(sig)
|
93
107
|
Sidekiq.logger.debug "Got #{sig} signal"
|
94
108
|
case sig
|
95
109
|
when 'INT'
|
96
|
-
if Sidekiq.options[:profile]
|
97
|
-
result = RubyProf.stop
|
98
|
-
printer = RubyProf::GraphHtmlPrinter.new(result)
|
99
|
-
File.open("profile.html", 'w') do |f|
|
100
|
-
printer.print(f, :min_percent => 1)
|
101
|
-
end
|
102
|
-
end
|
103
110
|
# Handle Ctrl-C in JRuby like MRI
|
104
111
|
# http://jira.codehaus.org/browse/JRUBY-4637
|
105
112
|
raise Interrupt
|
@@ -109,6 +116,7 @@ module Sidekiq
|
|
109
116
|
when 'USR1'
|
110
117
|
Sidekiq.logger.info "Received USR1, no longer accepting new work"
|
111
118
|
launcher.manager.async.stop
|
119
|
+
fire_event(:quiet)
|
112
120
|
when 'USR2'
|
113
121
|
if Sidekiq.options[:logfile]
|
114
122
|
Sidekiq.logger.info "Received USR2, reopening log file"
|
@@ -258,10 +266,6 @@ module Sidekiq
|
|
258
266
|
opts[:index] = Integer(arg.match(/\d+/)[0])
|
259
267
|
end
|
260
268
|
|
261
|
-
o.on '-p', '--profile', "Profile all code run by Sidekiq" do |arg|
|
262
|
-
opts[:profile] = arg
|
263
|
-
end
|
264
|
-
|
265
269
|
o.on "-q", "--queue QUEUE[,WEIGHT]", "Queues to process with optional weights" do |arg|
|
266
270
|
queue, weight = arg.split(",")
|
267
271
|
parse_queue opts, queue, weight
|
@@ -310,7 +314,7 @@ module Sidekiq
|
|
310
314
|
def initialize_logger
|
311
315
|
Sidekiq::Logging.initialize_logger(options[:logfile]) if options[:logfile]
|
312
316
|
|
313
|
-
Sidekiq.logger.level = Logger::DEBUG if options[:verbose]
|
317
|
+
Sidekiq.logger.level = ::Logger::DEBUG if options[:verbose]
|
314
318
|
end
|
315
319
|
|
316
320
|
def write_pid
|
data/lib/sidekiq/client.rb
CHANGED
@@ -25,6 +25,24 @@ module Sidekiq
|
|
25
25
|
@chain
|
26
26
|
end
|
27
27
|
|
28
|
+
attr_accessor :redis_pool
|
29
|
+
|
30
|
+
# Sidekiq::Client normally uses the default Redis pool but you may
|
31
|
+
# pass a custom ConnectionPool if you want to shard your
|
32
|
+
# Sidekiq jobs across several Redis instances (for scalability
|
33
|
+
# reasons, e.g.)
|
34
|
+
#
|
35
|
+
# Sidekiq::Client.new(ConnectionPool.new { Redis.new })
|
36
|
+
#
|
37
|
+
# Generally this is only needed for very large Sidekiq installs processing
|
38
|
+
# more than thousands jobs per second. I do not recommend sharding unless
|
39
|
+
# you truly cannot scale any other way (e.g. splitting your app into smaller apps).
|
40
|
+
# Some features, like the API, do not support sharding: they are designed to work
|
41
|
+
# against a single Redis instance only.
|
42
|
+
def initialize(redis_pool=nil)
|
43
|
+
@redis_pool = redis_pool || Thread.current[:sidekiq_via_pool] || Sidekiq.redis_pool
|
44
|
+
end
|
45
|
+
|
28
46
|
##
|
29
47
|
# The main method used to push a job to Redis. Accepts a number of options:
|
30
48
|
#
|
@@ -77,23 +95,35 @@ module Sidekiq
|
|
77
95
|
pushed ? payloads.collect { |payload| payload['jid'] } : nil
|
78
96
|
end
|
79
97
|
|
98
|
+
# Allows sharding of jobs across any number of Redis instances. All jobs
|
99
|
+
# defined within the block will use the given Redis connection pool.
|
100
|
+
#
|
101
|
+
# pool = ConnectionPool.new { Redis.new }
|
102
|
+
# Sidekiq::Client.via(pool) do
|
103
|
+
# SomeWorker.perform_async(1,2,3)
|
104
|
+
# SomeOtherWorker.perform_async(1,2,3)
|
105
|
+
# end
|
106
|
+
#
|
107
|
+
# Generally this is only needed for very large Sidekiq installs processing
|
108
|
+
# more than thousands jobs per second. I do not recommend sharding unless
|
109
|
+
# you truly cannot scale any other way (e.g. splitting your app into smaller apps).
|
110
|
+
# Some features, like the API, do not support sharding: they are designed to work
|
111
|
+
# against a single Redis instance.
|
112
|
+
def self.via(pool)
|
113
|
+
raise ArgumentError, "No pool given" if pool.nil?
|
114
|
+
raise RuntimeError, "Sidekiq::Client.via is not re-entrant" if x = Thread.current[:sidekiq_via_pool] && x != pool
|
115
|
+
Thread.current[:sidekiq_via_pool] = pool
|
116
|
+
yield
|
117
|
+
ensure
|
118
|
+
Thread.current[:sidekiq_via_pool] = nil
|
119
|
+
end
|
120
|
+
|
80
121
|
class << self
|
122
|
+
|
81
123
|
def default
|
82
124
|
@default ||= new
|
83
125
|
end
|
84
126
|
|
85
|
-
# deprecated
|
86
|
-
def registered_workers
|
87
|
-
puts "registered_workers is deprecated, please use Sidekiq::Workers.new"
|
88
|
-
Sidekiq.redis { |x| x.smembers('workers') }
|
89
|
-
end
|
90
|
-
|
91
|
-
# deprecated
|
92
|
-
def registered_queues
|
93
|
-
puts "registered_queues is deprecated, please use Sidekiq::Queue.all"
|
94
|
-
Sidekiq::Queue.all.map(&:name)
|
95
|
-
end
|
96
|
-
|
97
127
|
def push(item)
|
98
128
|
default.push(item)
|
99
129
|
end
|
@@ -147,7 +177,7 @@ module Sidekiq
|
|
147
177
|
|
148
178
|
def raw_push(payloads)
|
149
179
|
pushed = false
|
150
|
-
|
180
|
+
@redis_pool.with do |conn|
|
151
181
|
if payloads.first['at']
|
152
182
|
pushed = conn.zadd('schedule', payloads.map do |hash|
|
153
183
|
at = hash.delete('at').to_s
|
@@ -168,7 +198,7 @@ module Sidekiq
|
|
168
198
|
def process_single(worker_class, item)
|
169
199
|
queue = item['queue']
|
170
200
|
|
171
|
-
middleware.invoke(worker_class, item, queue) do
|
201
|
+
middleware.invoke(worker_class, item, queue, @redis_pool) do
|
172
202
|
item
|
173
203
|
end
|
174
204
|
end
|
data/lib/sidekiq/core_ext.rb
CHANGED
@@ -6,7 +6,6 @@ rescue LoadError
|
|
6
6
|
# Class#class_attribute helper.
|
7
7
|
class Class
|
8
8
|
def class_attribute(*attrs)
|
9
|
-
instance_reader = true
|
10
9
|
instance_writer = true
|
11
10
|
|
12
11
|
attrs.each do |name|
|
@@ -29,14 +28,12 @@ rescue LoadError
|
|
29
28
|
val
|
30
29
|
end
|
31
30
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
end
|
31
|
+
def #{name}
|
32
|
+
defined?(@#{name}) ? @#{name} : self.class.#{name}
|
33
|
+
end
|
36
34
|
|
37
|
-
|
38
|
-
|
39
|
-
end
|
35
|
+
def #{name}?
|
36
|
+
!!#{name}
|
40
37
|
end
|
41
38
|
RUBY
|
42
39
|
|
@@ -1,39 +1,30 @@
|
|
1
|
+
require 'sidekiq'
|
2
|
+
|
1
3
|
module Sidekiq
|
2
4
|
module ExceptionHandler
|
3
5
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
# middleware like BugSnag does:
|
11
|
-
# https://github.com/bugsnag/bugsnag-ruby/blob/master/lib/bugsnag/sidekiq.rb
|
12
|
-
send_to_airbrake(ctxHash, ex) if defined?(::Airbrake)
|
13
|
-
send_to_honeybadger(ctxHash, ex) if defined?(::Honeybadger)
|
14
|
-
send_to_exceptional(ctxHash, ex) if defined?(::Exceptional)
|
15
|
-
send_to_exception_notifier(ctxHash, ex) if defined?(::ExceptionNotifier)
|
16
|
-
end
|
17
|
-
|
18
|
-
private
|
19
|
-
|
20
|
-
def send_to_airbrake(hash, ex)
|
21
|
-
::Airbrake.notify_or_ignore(ex, :parameters => hash)
|
22
|
-
end
|
6
|
+
class Logger
|
7
|
+
def call(ex, ctxHash)
|
8
|
+
Sidekiq.logger.warn(ctxHash) if !ctxHash.empty?
|
9
|
+
Sidekiq.logger.warn ex
|
10
|
+
Sidekiq.logger.warn ex.backtrace.join("\n") unless ex.backtrace.nil?
|
11
|
+
end
|
23
12
|
|
24
|
-
|
25
|
-
|
13
|
+
# Set up default handler which just logs the error
|
14
|
+
Sidekiq.error_handlers << Sidekiq::ExceptionHandler::Logger.new
|
26
15
|
end
|
27
16
|
|
28
|
-
def
|
29
|
-
|
30
|
-
|
31
|
-
|
17
|
+
def handle_exception(ex, ctxHash={})
|
18
|
+
Sidekiq.error_handlers.each do |handler|
|
19
|
+
begin
|
20
|
+
handler.call(ex, ctxHash)
|
21
|
+
rescue => ex
|
22
|
+
Sidekiq.logger.error "!!! ERROR HANDLER THREW AN ERROR !!!"
|
23
|
+
Sidekiq.logger.error ex
|
24
|
+
Sidekiq.logger.error ex.backtrace.join("\n") unless ex.backtrace.nil?
|
25
|
+
end
|
32
26
|
end
|
33
27
|
end
|
34
28
|
|
35
|
-
def send_to_exception_notifier(hash, ex)
|
36
|
-
::ExceptionNotifier.notify_exception(ex, :data => {:message => hash})
|
37
|
-
end
|
38
29
|
end
|
39
30
|
end
|
data/lib/sidekiq/fetch.rb
CHANGED
@@ -140,10 +140,10 @@ module Sidekiq
|
|
140
140
|
end
|
141
141
|
end
|
142
142
|
|
143
|
-
# Creating the Redis#
|
144
|
-
# configured queue weights. By default Redis#
|
143
|
+
# Creating the Redis#brpop command takes into account any
|
144
|
+
# configured queue weights. By default Redis#brpop returns
|
145
145
|
# data from the first queue that has pending elements. We
|
146
|
-
# recreate the queue command each time we invoke Redis#
|
146
|
+
# recreate the queue command each time we invoke Redis#brpop
|
147
147
|
# to honor weights and avoid queue starvation.
|
148
148
|
def queues_cmd
|
149
149
|
queues = @strictly_ordered_queues ? @unique_queues.dup : @queues.shuffle.uniq
|
data/lib/sidekiq/launcher.rb
CHANGED
@@ -36,6 +36,8 @@ module Sidekiq
|
|
36
36
|
watchdog('Launcher#run') do
|
37
37
|
manager.async.start
|
38
38
|
poller.async.poll(true)
|
39
|
+
|
40
|
+
start_heartbeat
|
39
41
|
end
|
40
42
|
end
|
41
43
|
|
@@ -51,12 +53,37 @@ module Sidekiq
|
|
51
53
|
|
52
54
|
# Requeue everything in case there was a worker who grabbed work while stopped
|
53
55
|
Sidekiq::Fetcher.strategy.bulk_requeue([], @options)
|
56
|
+
|
57
|
+
stop_heartbeat
|
54
58
|
end
|
55
59
|
end
|
56
60
|
|
57
|
-
|
58
|
-
|
59
|
-
|
61
|
+
private
|
62
|
+
|
63
|
+
def start_heartbeat
|
64
|
+
key = identity
|
65
|
+
data = {
|
66
|
+
'hostname' => hostname,
|
67
|
+
'started_at' => Time.now.to_f,
|
68
|
+
'pid' => $$,
|
69
|
+
'tag' => @options[:tag] || '',
|
70
|
+
'concurrency' => @options[:concurrency],
|
71
|
+
'queues' => @options[:queues].uniq,
|
72
|
+
}
|
73
|
+
Sidekiq.redis do |conn|
|
74
|
+
conn.multi do
|
75
|
+
conn.sadd('processes', key)
|
76
|
+
conn.hset(key, 'info', Sidekiq.dump_json(data))
|
77
|
+
conn.expire(key, 60)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
manager.heartbeat(key, data)
|
81
|
+
end
|
82
|
+
|
83
|
+
def stop_heartbeat
|
84
|
+
Sidekiq.redis do |conn|
|
85
|
+
conn.srem('processes', identity)
|
86
|
+
end
|
60
87
|
end
|
61
88
|
end
|
62
89
|
end
|
data/lib/sidekiq/logging.rb
CHANGED
@@ -26,7 +26,7 @@ module Sidekiq
|
|
26
26
|
end
|
27
27
|
|
28
28
|
def self.initialize_logger(log_target = STDOUT)
|
29
|
-
oldlogger = @logger
|
29
|
+
oldlogger = defined?(@logger) ? @logger : nil
|
30
30
|
@logger = Logger.new(log_target)
|
31
31
|
@logger.level = Logger::INFO
|
32
32
|
@logger.formatter = Pretty.new
|
@@ -35,7 +35,7 @@ module Sidekiq
|
|
35
35
|
end
|
36
36
|
|
37
37
|
def self.logger
|
38
|
-
@logger
|
38
|
+
defined?(@logger) ? @logger : initialize_logger
|
39
39
|
end
|
40
40
|
|
41
41
|
def self.logger=(log)
|
data/lib/sidekiq/manager.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# encoding: utf-8
|
1
2
|
require 'sidekiq/util'
|
2
3
|
require 'sidekiq/actor'
|
3
4
|
require 'sidekiq/processor'
|
@@ -49,7 +50,6 @@ module Sidekiq
|
|
49
50
|
@ready.each { |x| x.terminate if x.alive? }
|
50
51
|
@ready.clear
|
51
52
|
|
52
|
-
clear_worker_set
|
53
53
|
return if clean_up_for_graceful_shutdown
|
54
54
|
|
55
55
|
hard_shutdown_in timeout if should_shutdown
|
@@ -132,27 +132,30 @@ module Sidekiq
|
|
132
132
|
@threads[proxy_id] = thr
|
133
133
|
end
|
134
134
|
|
135
|
-
def
|
136
|
-
|
135
|
+
def heartbeat(key, data)
|
136
|
+
return if stopped?
|
137
|
+
|
138
|
+
$0 = "sidekiq #{Sidekiq::VERSION} #{data['tag']}[#{@busy.size} of #{data['concurrency']} busy]#{stopped? ? ' stopping' : ''}"
|
139
|
+
❤(key)
|
140
|
+
after(5) do
|
141
|
+
heartbeat(key, data)
|
142
|
+
end
|
137
143
|
end
|
138
144
|
|
139
145
|
private
|
140
146
|
|
141
|
-
def
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
workers = conn.smembers('workers')
|
149
|
-
workers_to_remove = workers.select do |worker_name|
|
150
|
-
worker_name =~ /:#{process_id}-/
|
147
|
+
def ❤(key)
|
148
|
+
begin
|
149
|
+
Sidekiq.redis do |conn|
|
150
|
+
conn.multi do
|
151
|
+
conn.hmset(key, 'busy', @busy.size, 'beat', Time.now.to_f)
|
152
|
+
conn.expire(key, 60)
|
153
|
+
end
|
151
154
|
end
|
152
|
-
|
155
|
+
rescue => e
|
156
|
+
# ignore all redis/network issues
|
157
|
+
logger.error("heartbeat: #{e.message}")
|
153
158
|
end
|
154
|
-
rescue => ex
|
155
|
-
Sidekiq.logger.warn("Unable to clear worker set while shutting down: #{ex.message}")
|
156
159
|
end
|
157
160
|
|
158
161
|
def hard_shutdown_in(delay)
|
@@ -108,17 +108,33 @@ module Sidekiq
|
|
108
108
|
|
109
109
|
private
|
110
110
|
|
111
|
+
DEAD_JOB_TIMEOUT = 180 * 24 * 60 * 60 # 6 months
|
112
|
+
MAX_JOBS = 10_000
|
113
|
+
|
111
114
|
def retries_exhausted(worker, msg)
|
112
115
|
logger.debug { "Dropping message after hitting the retry maximum: #{msg}" }
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
116
|
+
begin
|
117
|
+
if worker.sidekiq_retries_exhausted_block?
|
118
|
+
worker.sidekiq_retries_exhausted_block.call(msg)
|
119
|
+
end
|
120
|
+
rescue => e
|
121
|
+
handle_exception(e, { :context => "Error calling retries_exhausted" })
|
118
122
|
end
|
119
123
|
|
120
|
-
|
121
|
-
|
124
|
+
send_to_morgue(msg)
|
125
|
+
end
|
126
|
+
|
127
|
+
def send_to_morgue(msg)
|
128
|
+
Sidekiq.logger.info { "Adding dead #{msg['class']} job #{msg['jid']}" }
|
129
|
+
payload = Sidekiq.dump_json(msg)
|
130
|
+
now = Time.now.to_f
|
131
|
+
Sidekiq.redis do |conn|
|
132
|
+
conn.multi do
|
133
|
+
conn.zadd('dead', now, payload)
|
134
|
+
conn.zremrangebyscore('dead', '-inf', now - DEAD_JOB_TIMEOUT)
|
135
|
+
conn.zremrangebyrank('dead', 0, -MAX_JOBS)
|
136
|
+
end
|
137
|
+
end
|
122
138
|
end
|
123
139
|
|
124
140
|
def retry_attempts_from(msg_retry, default)
|