sidekiq 5.0.1 → 5.2.9
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 +5 -5
- data/.circleci/config.yml +61 -0
- data/.github/issue_template.md +3 -1
- data/.gitignore +2 -0
- data/.travis.yml +6 -13
- data/COMM-LICENSE +11 -9
- data/Changes.md +136 -1
- data/Ent-Changes.md +46 -3
- data/Gemfile +14 -20
- data/LICENSE +1 -1
- data/Pro-4.0-Upgrade.md +35 -0
- data/Pro-Changes.md +125 -0
- data/README.md +5 -3
- data/Rakefile +2 -5
- data/bin/sidekiqctl +13 -92
- data/bin/sidekiqload +2 -2
- data/lib/sidekiq.rb +24 -15
- data/lib/sidekiq/api.rb +83 -37
- data/lib/sidekiq/cli.rb +106 -76
- data/lib/sidekiq/client.rb +36 -33
- data/lib/sidekiq/ctl.rb +221 -0
- data/lib/sidekiq/delay.rb +23 -2
- data/lib/sidekiq/exception_handler.rb +2 -4
- data/lib/sidekiq/fetch.rb +1 -1
- data/lib/sidekiq/job_logger.rb +4 -3
- data/lib/sidekiq/job_retry.rb +51 -24
- data/lib/sidekiq/launcher.rb +18 -12
- data/lib/sidekiq/logging.rb +9 -5
- data/lib/sidekiq/manager.rb +5 -6
- data/lib/sidekiq/middleware/server/active_record.rb +2 -1
- data/lib/sidekiq/processor.rb +85 -48
- data/lib/sidekiq/rails.rb +7 -0
- data/lib/sidekiq/redis_connection.rb +40 -4
- data/lib/sidekiq/scheduled.rb +35 -8
- data/lib/sidekiq/testing.rb +4 -4
- data/lib/sidekiq/util.rb +5 -1
- data/lib/sidekiq/version.rb +1 -1
- data/lib/sidekiq/web.rb +4 -4
- data/lib/sidekiq/web/action.rb +2 -2
- data/lib/sidekiq/web/application.rb +24 -2
- data/lib/sidekiq/web/helpers.rb +18 -8
- data/lib/sidekiq/web/router.rb +10 -10
- data/lib/sidekiq/worker.rb +39 -22
- data/sidekiq.gemspec +6 -17
- data/web/assets/javascripts/application.js +0 -0
- data/web/assets/javascripts/dashboard.js +15 -5
- data/web/assets/stylesheets/application.css +35 -2
- data/web/assets/stylesheets/bootstrap.css +2 -2
- data/web/locales/ar.yml +1 -0
- data/web/locales/en.yml +2 -0
- data/web/locales/es.yml +4 -3
- data/web/locales/ja.yml +5 -3
- data/web/views/_footer.erb +3 -0
- data/web/views/_nav.erb +3 -17
- data/web/views/layout.erb +1 -1
- data/web/views/queue.erb +1 -0
- data/web/views/queues.erb +2 -0
- data/web/views/retries.erb +4 -0
- metadata +20 -156
data/Pro-Changes.md
CHANGED
@@ -4,6 +4,131 @@
|
|
4
4
|
|
5
5
|
Please see [http://sidekiq.org/](http://sidekiq.org/) for more details and how to buy.
|
6
6
|
|
7
|
+
HEAD
|
8
|
+
---------
|
9
|
+
|
10
|
+
- Add ES translations, see issues [#3949](https://github.com/mperham/sidekiq/issues/3949) and [#3951](https://github.com/mperham/sidekiq/issues/3951) to add your own language.
|
11
|
+
|
12
|
+
4.0.5
|
13
|
+
---------
|
14
|
+
|
15
|
+
- Increase super\_fetch retriever thread count from 1 to 2 to make it
|
16
|
+
less sensitive to Redis latency.
|
17
|
+
- Better handling of invalid job JSON by reliable scheduler [#4053]
|
18
|
+
- Added ZH, PT, JA and RU translations.
|
19
|
+
|
20
|
+
4.0.4
|
21
|
+
---------
|
22
|
+
|
23
|
+
- Update Sidekiq::Client patches to work with new Module#prepend
|
24
|
+
mechanism in Sidekiq 5.2.0. [#3930]
|
25
|
+
|
26
|
+
4.0.3
|
27
|
+
---------
|
28
|
+
|
29
|
+
- Add at\_exit handler to push any saved jobs in `reliable_push` when exiting. [#3823]
|
30
|
+
- Implement batch death callback. This is fired the first time a job within a batch dies. [#3841]
|
31
|
+
```ruby
|
32
|
+
batch = Sidekiq::Batch.new
|
33
|
+
batch.on(:death, ...)
|
34
|
+
```
|
35
|
+
|
36
|
+
4.0.2
|
37
|
+
---------
|
38
|
+
|
39
|
+
- Remove super\_fetch edge case leading to an unnecessary `sleep(1)`
|
40
|
+
call and resulting latency [#3790]
|
41
|
+
- Fix possible bad statsd metric call on super\_fetch startup
|
42
|
+
- Remove superfluous `freeze` calls on Strings [#3759]
|
43
|
+
|
44
|
+
4.0.1
|
45
|
+
---------
|
46
|
+
|
47
|
+
- Fix incompatibility with the statsd-ruby gem [#3740]
|
48
|
+
- Add tags to Statsd metrics when using Datadog [#3744]
|
49
|
+
|
50
|
+
4.0.0
|
51
|
+
---------
|
52
|
+
|
53
|
+
- See the [Sidekiq Pro 4.0](Pro-4.0-Upgrade.md) release notes.
|
54
|
+
|
55
|
+
|
56
|
+
3.7.1
|
57
|
+
---------
|
58
|
+
|
59
|
+
- Deprecate timed\_fetch. Switch to super\_fetch:
|
60
|
+
```ruby
|
61
|
+
config.super_fetch!
|
62
|
+
```
|
63
|
+
|
64
|
+
|
65
|
+
3.7.0
|
66
|
+
---------
|
67
|
+
|
68
|
+
- Refactor batch job success/failure to gracefully handle several edge
|
69
|
+
cases with regard to Sidekiq::Shutdown. This should greatly reduce
|
70
|
+
the chances of seeing the long-standing "negative pending count" problem. [#3710]
|
71
|
+
|
72
|
+
|
73
|
+
3.6.1
|
74
|
+
---------
|
75
|
+
|
76
|
+
- Add support for Datadog::Statsd, it is the recommended Statsd client. [#3699]
|
77
|
+
```ruby
|
78
|
+
Sidekiq::Pro.dogstatsd = ->{ Datadog::Statsd.new("metrics.example.com", 8125) }
|
79
|
+
```
|
80
|
+
- Size the statsd connection pool based on Sidekiq's concurrency [#3700]
|
81
|
+
|
82
|
+
|
83
|
+
3.6.0
|
84
|
+
---------
|
85
|
+
|
86
|
+
This release overhauls the Statsd metrics support and adds more
|
87
|
+
metrics for tracking Pro feature usage. In your initializer:
|
88
|
+
```ruby
|
89
|
+
Sidekiq::Pro.statsd = ->{ ::Statsd.new("127.0.0.1", 8125) }
|
90
|
+
```
|
91
|
+
Sidekiq Pro will emit more metrics to Statsd:
|
92
|
+
```
|
93
|
+
jobs.expired - when a job is expired
|
94
|
+
jobs.recovered.push - when a job is recovered by reliable_push after network outage
|
95
|
+
jobs.recovered.fetch - when a job is recovered by super_fetch after process crash
|
96
|
+
batch.created - when a batch is created
|
97
|
+
batch.complete - when a batch is completed
|
98
|
+
batch.success - when a batch is successful
|
99
|
+
```
|
100
|
+
Sidekiq Pro's existing Statsd middleware has been rewritten to leverage the new API.
|
101
|
+
Everything should be backwards compatible with one deprecation notice.
|
102
|
+
|
103
|
+
|
104
|
+
3.5.4
|
105
|
+
---------
|
106
|
+
|
107
|
+
- Fix case in SuperFetch where Redis downtime can lead to processor thread death [#3684]
|
108
|
+
- Fix case where TimedFetch might not recover some pending jobs
|
109
|
+
- Fix edge case in Batch::Status#poll leading to premature completion [#3640]
|
110
|
+
- Adjust scan API to check 100 elements at a time, to minimize network round trips
|
111
|
+
when scanning large sets.
|
112
|
+
|
113
|
+
3.5.3
|
114
|
+
---------
|
115
|
+
|
116
|
+
- Restore error check for super\_fetch's job ack [#3601]
|
117
|
+
- Trim error messages saved in Batch's failure hash, preventing huge
|
118
|
+
messages from bloating Redis. [#3570]
|
119
|
+
|
120
|
+
3.5.2
|
121
|
+
---------
|
122
|
+
|
123
|
+
- Fix `Status#completed?` when run against a Batch that had succeeded
|
124
|
+
and was deleted. [#3519]
|
125
|
+
|
126
|
+
3.5.1
|
127
|
+
---------
|
128
|
+
|
129
|
+
- Work with Sidekiq 5.0.2+
|
130
|
+
- Improve performance of super\_fetch with weighted queues [#3489]
|
131
|
+
|
7
132
|
3.5.0
|
8
133
|
---------
|
9
134
|
|
data/README.md
CHANGED
@@ -3,7 +3,7 @@ Sidekiq
|
|
3
3
|
|
4
4
|
[![Gem Version](https://badge.fury.io/rb/sidekiq.svg)](https://rubygems.org/gems/sidekiq)
|
5
5
|
[![Code Climate](https://codeclimate.com/github/mperham/sidekiq.svg)](https://codeclimate.com/github/mperham/sidekiq)
|
6
|
-
[![Build Status](https://
|
6
|
+
[![Build Status](https://circleci.com/gh/mperham/sidekiq/tree/master.svg?style=svg)](https://circleci.com/gh/mperham/sidekiq/tree/master)
|
7
7
|
[![Gitter Chat](https://badges.gitter.im/mperham/sidekiq.svg)](https://gitter.im/mperham/sidekiq)
|
8
8
|
|
9
9
|
|
@@ -77,16 +77,18 @@ Problems?
|
|
77
77
|
If you have a problem, please review the [FAQ](https://github.com/mperham/sidekiq/wiki/FAQ) and [Troubleshooting](https://github.com/mperham/sidekiq/wiki/Problems-and-Troubleshooting) wiki pages.
|
78
78
|
Searching the [issues](https://github.com/mperham/sidekiq/issues) for your problem is also a good idea.
|
79
79
|
|
80
|
+
Sidekiq Pro and Sidekiq Enterprise customers get private email support. You can purchase at http://sidekiq.org; email support@contribsys.com for help.
|
81
|
+
|
80
82
|
Useful resources:
|
81
83
|
|
82
84
|
* Product documentation is in the [wiki](https://github.com/mperham/sidekiq/wiki).
|
83
85
|
* Release announcements are made to the [@sidekiq](https://twitter.com/sidekiq) Twitter account.
|
84
86
|
* The [Sidekiq tag](https://stackoverflow.com/questions/tagged/sidekiq) on Stack Overflow has lots of useful Q & A.
|
85
87
|
|
86
|
-
**No support via Twitter
|
88
|
+
**No support via Twitter**
|
87
89
|
|
88
90
|
Every Friday morning is Sidekiq happy hour: I video chat and answer questions.
|
89
|
-
See the [Sidekiq support page](http://sidekiq.org/support) for details.
|
91
|
+
See the [Sidekiq support page](http://sidekiq.org/support.html) for details.
|
90
92
|
|
91
93
|
Thanks
|
92
94
|
-----------------
|
data/Rakefile
CHANGED
@@ -1,12 +1,9 @@
|
|
1
1
|
require 'bundler/gem_tasks'
|
2
2
|
require 'rake/testtask'
|
3
|
+
|
3
4
|
Rake::TestTask.new(:test) do |test|
|
4
5
|
test.warning = true
|
5
6
|
test.pattern = 'test/**/test_*.rb'
|
6
7
|
end
|
7
8
|
|
8
|
-
task :
|
9
|
-
|
10
|
-
task :appraise do
|
11
|
-
exec("cd myapp && rake appraise")
|
12
|
-
end
|
9
|
+
task default: :test
|
data/bin/sidekiqctl
CHANGED
@@ -1,99 +1,20 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
3
|
require 'fileutils'
|
4
|
+
require 'sidekiq/api'
|
5
|
+
require 'sidekiq/ctl'
|
4
6
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
attr_reader :stage, :pidfile, :kill_timeout
|
9
|
-
|
10
|
-
def self.print_usage
|
11
|
-
puts "#{File.basename($0)} - stop a Sidekiq process from the command line."
|
12
|
-
puts
|
13
|
-
puts "Usage: #{File.basename($0)} <command> <pidfile> <kill_timeout>"
|
14
|
-
puts " where <command> is either 'quiet' or 'stop'"
|
15
|
-
puts " <pidfile> is path to a pidfile"
|
16
|
-
puts " <kill_timeout> is number of seconds to wait until Sidekiq exits"
|
17
|
-
puts " (default: #{Sidekiqctl::DEFAULT_KILL_TIMEOUT}), after which Sidekiq will be KILL'd"
|
18
|
-
puts
|
19
|
-
puts "Be sure to set the kill_timeout LONGER than Sidekiq's -t timeout. If you want"
|
20
|
-
puts "to wait 60 seconds for jobs to finish, use `sidekiq -t 60` and `sidekiqctl stop"
|
21
|
-
puts " path_to_pidfile 61`"
|
22
|
-
puts
|
23
|
-
end
|
24
|
-
|
25
|
-
def initialize(stage, pidfile, timeout)
|
26
|
-
@stage = stage
|
27
|
-
@pidfile = pidfile
|
28
|
-
@kill_timeout = timeout
|
29
|
-
|
30
|
-
done('No pidfile given', :error) if !pidfile
|
31
|
-
done("Pidfile #{pidfile} does not exist", :warn) if !File.exist?(pidfile)
|
32
|
-
done('Invalid pidfile content', :error) if pid == 0
|
33
|
-
|
34
|
-
fetch_process
|
35
|
-
|
36
|
-
begin
|
37
|
-
send(stage)
|
38
|
-
rescue NoMethodError
|
39
|
-
done "Invalid command: #{stage}", :error
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
def fetch_process
|
44
|
-
Process.kill(0, pid)
|
45
|
-
rescue Errno::ESRCH
|
46
|
-
done "Process doesn't exist", :error
|
47
|
-
# We were not allowed to send a signal, but the process must have existed
|
48
|
-
# when Process.kill() was called.
|
49
|
-
rescue Errno::EPERM
|
50
|
-
return pid
|
51
|
-
end
|
52
|
-
|
53
|
-
def done(msg, error = nil)
|
54
|
-
puts msg
|
55
|
-
exit(exit_signal(error))
|
56
|
-
end
|
57
|
-
|
58
|
-
def exit_signal(error)
|
59
|
-
(error == :error) ? 1 : 0
|
60
|
-
end
|
61
|
-
|
62
|
-
def pid
|
63
|
-
@pid ||= File.read(pidfile).to_i
|
64
|
-
end
|
65
|
-
|
66
|
-
def quiet
|
67
|
-
`kill -TSTP #{pid}`
|
68
|
-
end
|
69
|
-
|
70
|
-
def stop
|
71
|
-
`kill -TERM #{pid}`
|
72
|
-
kill_timeout.times do
|
73
|
-
begin
|
74
|
-
Process.kill(0, pid)
|
75
|
-
rescue Errno::ESRCH
|
76
|
-
FileUtils.rm_f pidfile
|
77
|
-
done 'Sidekiq shut down gracefully.'
|
78
|
-
rescue Errno::EPERM
|
79
|
-
done 'Not permitted to shut down Sidekiq.'
|
80
|
-
end
|
81
|
-
sleep 1
|
82
|
-
end
|
83
|
-
`kill -9 #{pid}`
|
84
|
-
FileUtils.rm_f pidfile
|
85
|
-
done 'Sidekiq shut down forcefully.'
|
86
|
-
end
|
87
|
-
alias_method :shutdown, :stop
|
88
|
-
end
|
89
|
-
|
90
|
-
if ARGV.length < 2
|
91
|
-
Sidekiqctl.print_usage
|
7
|
+
if ARGV[0] == 'status'
|
8
|
+
Sidekiq::Ctl::Status.new.display(ARGV[1])
|
92
9
|
else
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
10
|
+
if ARGV.length < 2
|
11
|
+
Sidekiq::Ctl.print_usage
|
12
|
+
else
|
13
|
+
stage = ARGV[0]
|
14
|
+
pidfile = ARGV[1]
|
15
|
+
timeout = ARGV[2].to_i
|
16
|
+
timeout = Sidekiq::Ctl::DEFAULT_KILL_TIMEOUT if timeout == 0
|
97
17
|
|
98
|
-
|
18
|
+
Sidekiq::Ctl.new(stage, pidfile, timeout)
|
19
|
+
end
|
99
20
|
end
|
data/bin/sidekiqload
CHANGED
@@ -65,14 +65,14 @@ def handle_signal(launcher, sig)
|
|
65
65
|
# http://jira.codehaus.org/browse/JRUBY-4637
|
66
66
|
raise Interrupt
|
67
67
|
when 'TERM'
|
68
|
-
# Heroku sends TERM and then waits
|
68
|
+
# Heroku sends TERM and then waits 30 seconds for process to exit.
|
69
69
|
raise Interrupt
|
70
70
|
when 'TSTP'
|
71
71
|
Sidekiq.logger.info "Received TSTP, no longer accepting new work"
|
72
72
|
launcher.quiet
|
73
73
|
when 'TTIN'
|
74
74
|
Thread.list.each do |thread|
|
75
|
-
Sidekiq.logger.warn "Thread TID-#{thread.object_id.to_s(36)} #{thread['label']}"
|
75
|
+
Sidekiq.logger.warn "Thread TID-#{(thread.object_id ^ ::Process.pid).to_s(36)} #{thread['label']}"
|
76
76
|
if thread.backtrace
|
77
77
|
Sidekiq.logger.warn thread.backtrace.join("\n")
|
78
78
|
else
|
data/lib/sidekiq.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
|
-
# encoding: utf-8
|
2
1
|
# frozen_string_literal: true
|
2
|
+
|
3
3
|
require 'sidekiq/version'
|
4
|
-
fail "Sidekiq #{Sidekiq::VERSION} does not support Ruby versions below 2.2.2." if RUBY_PLATFORM != 'java' && RUBY_VERSION < '2.2.2'
|
4
|
+
fail "Sidekiq #{Sidekiq::VERSION} does not support Ruby versions below 2.2.2." if RUBY_PLATFORM != 'java' && Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.2.2')
|
5
5
|
|
6
6
|
require 'sidekiq/logging'
|
7
7
|
require 'sidekiq/client'
|
@@ -12,19 +12,20 @@ require 'sidekiq/delay'
|
|
12
12
|
require 'json'
|
13
13
|
|
14
14
|
module Sidekiq
|
15
|
-
NAME = 'Sidekiq'
|
15
|
+
NAME = 'Sidekiq'
|
16
16
|
LICENSE = 'See LICENSE and the LGPL-3.0 for licensing details.'
|
17
17
|
|
18
18
|
DEFAULTS = {
|
19
19
|
queues: [],
|
20
20
|
labels: [],
|
21
|
-
concurrency:
|
21
|
+
concurrency: 10,
|
22
22
|
require: '.',
|
23
23
|
environment: nil,
|
24
24
|
timeout: 8,
|
25
25
|
poll_interval_average: nil,
|
26
|
-
average_scheduled_poll_interval:
|
26
|
+
average_scheduled_poll_interval: 5,
|
27
27
|
error_handlers: [],
|
28
|
+
death_handlers: [],
|
28
29
|
lifecycle_events: {
|
29
30
|
startup: [],
|
30
31
|
quiet: [],
|
@@ -47,7 +48,7 @@ module Sidekiq
|
|
47
48
|
"connected_clients" => "9999",
|
48
49
|
"used_memory_human" => "9P",
|
49
50
|
"used_memory_peak_human" => "9P"
|
50
|
-
}
|
51
|
+
}
|
51
52
|
|
52
53
|
def self.❨╯°□°❩╯︵┻━┻
|
53
54
|
puts "Calm down, yo."
|
@@ -56,6 +57,7 @@ module Sidekiq
|
|
56
57
|
def self.options
|
57
58
|
@options ||= DEFAULTS.dup
|
58
59
|
end
|
60
|
+
|
59
61
|
def self.options=(opts)
|
60
62
|
@options = opts
|
61
63
|
end
|
@@ -94,8 +96,8 @@ module Sidekiq
|
|
94
96
|
begin
|
95
97
|
yield conn
|
96
98
|
rescue Redis::CommandError => ex
|
97
|
-
#2550 Failover can cause the server to become a
|
98
|
-
# to disconnect and reopen the socket to get back to the
|
99
|
+
#2550 Failover can cause the server to become a replica, need
|
100
|
+
# to disconnect and reopen the socket to get back to the primary.
|
99
101
|
(conn.disconnect!; retryable = false; retry) if retryable && ex.message =~ /READONLY/
|
100
102
|
raise
|
101
103
|
end
|
@@ -156,16 +158,23 @@ module Sidekiq
|
|
156
158
|
defined?(@default_worker_options) ? @default_worker_options : DEFAULT_WORKER_OPTIONS
|
157
159
|
end
|
158
160
|
|
161
|
+
def self.default_retries_exhausted=(prok)
|
162
|
+
logger.info { "default_retries_exhausted is deprecated, please use `config.death_handlers << -> {|job, ex| }`" }
|
163
|
+
return nil unless prok
|
164
|
+
death_handlers << prok
|
165
|
+
end
|
166
|
+
|
167
|
+
##
|
168
|
+
# Death handlers are called when all retries for a job have been exhausted and
|
169
|
+
# the job dies. It's the notification to your application
|
170
|
+
# that this job will not succeed without manual intervention.
|
171
|
+
#
|
159
172
|
# Sidekiq.configure_server do |config|
|
160
|
-
# config.
|
173
|
+
# config.death_handlers << ->(job, ex) do
|
161
174
|
# end
|
162
175
|
# end
|
163
|
-
def self.
|
164
|
-
|
165
|
-
end
|
166
|
-
@default_retries_exhausted = ->(job, ex) { }
|
167
|
-
def self.default_retries_exhausted
|
168
|
-
@default_retries_exhausted
|
176
|
+
def self.death_handlers
|
177
|
+
options[:death_handlers]
|
169
178
|
end
|
170
179
|
|
171
180
|
def self.load_json(string)
|
data/lib/sidekiq/api.rb
CHANGED
@@ -1,9 +1,24 @@
|
|
1
|
-
# encoding: utf-8
|
2
1
|
# frozen_string_literal: true
|
3
2
|
require 'sidekiq'
|
4
3
|
|
5
4
|
module Sidekiq
|
5
|
+
|
6
|
+
module RedisScanner
|
7
|
+
def sscan(conn, key)
|
8
|
+
cursor = '0'
|
9
|
+
result = []
|
10
|
+
loop do
|
11
|
+
cursor, values = conn.sscan(key, cursor)
|
12
|
+
result.push(*values)
|
13
|
+
break if cursor == '0'
|
14
|
+
end
|
15
|
+
result
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
6
19
|
class Stats
|
20
|
+
include RedisScanner
|
21
|
+
|
7
22
|
def initialize
|
8
23
|
fetch_stats!
|
9
24
|
end
|
@@ -51,33 +66,39 @@ module Sidekiq
|
|
51
66
|
def fetch_stats!
|
52
67
|
pipe1_res = Sidekiq.redis do |conn|
|
53
68
|
conn.pipelined do
|
54
|
-
conn.get('stat:processed'
|
55
|
-
conn.get('stat:failed'
|
56
|
-
conn.zcard('schedule'
|
57
|
-
conn.zcard('retry'
|
58
|
-
conn.zcard('dead'
|
59
|
-
conn.scard('processes'
|
60
|
-
conn.lrange('queue:default'
|
61
|
-
conn.smembers('processes'.freeze)
|
62
|
-
conn.smembers('queues'.freeze)
|
69
|
+
conn.get('stat:processed')
|
70
|
+
conn.get('stat:failed')
|
71
|
+
conn.zcard('schedule')
|
72
|
+
conn.zcard('retry')
|
73
|
+
conn.zcard('dead')
|
74
|
+
conn.scard('processes')
|
75
|
+
conn.lrange('queue:default', -1, -1)
|
63
76
|
end
|
64
77
|
end
|
65
78
|
|
79
|
+
processes = Sidekiq.redis do |conn|
|
80
|
+
sscan(conn, 'processes')
|
81
|
+
end
|
82
|
+
|
83
|
+
queues = Sidekiq.redis do |conn|
|
84
|
+
sscan(conn, 'queues')
|
85
|
+
end
|
86
|
+
|
66
87
|
pipe2_res = Sidekiq.redis do |conn|
|
67
88
|
conn.pipelined do
|
68
|
-
|
69
|
-
|
89
|
+
processes.each {|key| conn.hget(key, 'busy') }
|
90
|
+
queues.each {|queue| conn.llen("queue:#{queue}") }
|
70
91
|
end
|
71
92
|
end
|
72
93
|
|
73
|
-
s =
|
94
|
+
s = processes.size
|
74
95
|
workers_size = pipe2_res[0...s].map(&:to_i).inject(0, &:+)
|
75
96
|
enqueued = pipe2_res[s..-1].map(&:to_i).inject(0, &:+)
|
76
97
|
|
77
98
|
default_queue_latency = if (entry = pipe1_res[6].first)
|
78
99
|
job = Sidekiq.load_json(entry) rescue {}
|
79
100
|
now = Time.now.to_f
|
80
|
-
thence = job['enqueued_at'
|
101
|
+
thence = job['enqueued_at'] || now
|
81
102
|
now - thence
|
82
103
|
else
|
83
104
|
0
|
@@ -117,9 +138,11 @@ module Sidekiq
|
|
117
138
|
end
|
118
139
|
|
119
140
|
class Queues
|
141
|
+
include RedisScanner
|
142
|
+
|
120
143
|
def lengths
|
121
144
|
Sidekiq.redis do |conn|
|
122
|
-
queues = conn
|
145
|
+
queues = sscan(conn, 'queues')
|
123
146
|
|
124
147
|
lengths = conn.pipelined do
|
125
148
|
queues.each do |queue|
|
@@ -163,7 +186,7 @@ module Sidekiq
|
|
163
186
|
|
164
187
|
while i < @days_previous
|
165
188
|
date = @start_date - i
|
166
|
-
datestr = date.strftime("%Y-%m-%d"
|
189
|
+
datestr = date.strftime("%Y-%m-%d")
|
167
190
|
keys << "stat:#{stat}:#{datestr}"
|
168
191
|
dates << datestr
|
169
192
|
i += 1
|
@@ -199,18 +222,19 @@ module Sidekiq
|
|
199
222
|
#
|
200
223
|
class Queue
|
201
224
|
include Enumerable
|
225
|
+
extend RedisScanner
|
202
226
|
|
203
227
|
##
|
204
228
|
# Return all known queues within Redis.
|
205
229
|
#
|
206
230
|
def self.all
|
207
|
-
Sidekiq.redis { |c| c
|
231
|
+
Sidekiq.redis { |c| sscan(c, 'queues') }.sort.map { |q| Sidekiq::Queue.new(q) }
|
208
232
|
end
|
209
233
|
|
210
234
|
attr_reader :name
|
211
235
|
|
212
236
|
def initialize(name="default")
|
213
|
-
@name = name
|
237
|
+
@name = name.to_s
|
214
238
|
@rname = "queue:#{name}"
|
215
239
|
end
|
216
240
|
|
@@ -273,7 +297,7 @@ module Sidekiq
|
|
273
297
|
Sidekiq.redis do |conn|
|
274
298
|
conn.multi do
|
275
299
|
conn.del(@rname)
|
276
|
-
conn.srem("queues"
|
300
|
+
conn.srem("queues", name)
|
277
301
|
end
|
278
302
|
end
|
279
303
|
end
|
@@ -335,7 +359,7 @@ module Sidekiq
|
|
335
359
|
|
336
360
|
def display_args
|
337
361
|
# Unwrap known wrappers so they show up in a human-friendly manner in the Web UI
|
338
|
-
@
|
362
|
+
@display_args ||= case klass
|
339
363
|
when /\ASidekiq::Extensions::Delayed/
|
340
364
|
safe_load(args[0], args) do |_, _, arg|
|
341
365
|
arg
|
@@ -349,9 +373,9 @@ module Sidekiq
|
|
349
373
|
job_args
|
350
374
|
end
|
351
375
|
else
|
352
|
-
if self['encrypt'
|
376
|
+
if self['encrypt']
|
353
377
|
# no point in showing 150+ bytes of random garbage
|
354
|
-
args[-1] = '[encrypted data]'
|
378
|
+
args[-1] = '[encrypted data]'
|
355
379
|
end
|
356
380
|
args
|
357
381
|
end
|
@@ -458,14 +482,7 @@ module Sidekiq
|
|
458
482
|
# Place job in the dead set
|
459
483
|
def kill
|
460
484
|
remove_job do |message|
|
461
|
-
|
462
|
-
Sidekiq.redis do |conn|
|
463
|
-
conn.multi do
|
464
|
-
conn.zadd('dead', now, message)
|
465
|
-
conn.zremrangebyscore('dead', '-inf', now - DeadSet.timeout)
|
466
|
-
conn.zremrangebyrank('dead', 0, - DeadSet.max_jobs)
|
467
|
-
end
|
468
|
-
end
|
485
|
+
DeadSet.new.kill(message)
|
469
486
|
end
|
470
487
|
end
|
471
488
|
|
@@ -555,7 +572,7 @@ module Sidekiq
|
|
555
572
|
end
|
556
573
|
break if elements.empty?
|
557
574
|
page -= 1
|
558
|
-
elements.each do |element, score|
|
575
|
+
elements.reverse.each do |element, score|
|
559
576
|
yield SortedEntry.new(self, score, element)
|
560
577
|
end
|
561
578
|
offset_size = initial_size - @_size
|
@@ -653,6 +670,12 @@ module Sidekiq
|
|
653
670
|
each(&:retry)
|
654
671
|
end
|
655
672
|
end
|
673
|
+
|
674
|
+
def kill_all
|
675
|
+
while size > 0
|
676
|
+
each(&:kill)
|
677
|
+
end
|
678
|
+
end
|
656
679
|
end
|
657
680
|
|
658
681
|
##
|
@@ -663,6 +686,27 @@ module Sidekiq
|
|
663
686
|
super 'dead'
|
664
687
|
end
|
665
688
|
|
689
|
+
def kill(message, opts={})
|
690
|
+
now = Time.now.to_f
|
691
|
+
Sidekiq.redis do |conn|
|
692
|
+
conn.multi do
|
693
|
+
conn.zadd(name, now.to_s, message)
|
694
|
+
conn.zremrangebyscore(name, '-inf', now - self.class.timeout)
|
695
|
+
conn.zremrangebyrank(name, 0, - self.class.max_jobs)
|
696
|
+
end
|
697
|
+
end
|
698
|
+
|
699
|
+
if opts[:notify_failure] != false
|
700
|
+
job = Sidekiq.load_json(message)
|
701
|
+
r = RuntimeError.new("Job killed by API")
|
702
|
+
r.set_backtrace(caller)
|
703
|
+
Sidekiq.death_handlers.each do |handle|
|
704
|
+
handle.call(job, r)
|
705
|
+
end
|
706
|
+
end
|
707
|
+
true
|
708
|
+
end
|
709
|
+
|
666
710
|
def retry_all
|
667
711
|
while size > 0
|
668
712
|
each(&:retry)
|
@@ -687,17 +731,18 @@ module Sidekiq
|
|
687
731
|
#
|
688
732
|
class ProcessSet
|
689
733
|
include Enumerable
|
734
|
+
include RedisScanner
|
690
735
|
|
691
736
|
def initialize(clean_plz=true)
|
692
|
-
|
737
|
+
cleanup if clean_plz
|
693
738
|
end
|
694
739
|
|
695
740
|
# Cleans up dead processes recorded in Redis.
|
696
741
|
# Returns the number of processes cleaned.
|
697
|
-
def
|
742
|
+
def cleanup
|
698
743
|
count = 0
|
699
744
|
Sidekiq.redis do |conn|
|
700
|
-
procs = conn
|
745
|
+
procs = sscan(conn, 'processes').sort
|
701
746
|
heartbeats = conn.pipelined do
|
702
747
|
procs.each do |key|
|
703
748
|
conn.hget(key, 'info')
|
@@ -717,7 +762,7 @@ module Sidekiq
|
|
717
762
|
end
|
718
763
|
|
719
764
|
def each
|
720
|
-
procs = Sidekiq.redis { |conn| conn
|
765
|
+
procs = Sidekiq.redis { |conn| sscan(conn, 'processes') }.sort
|
721
766
|
|
722
767
|
Sidekiq.redis do |conn|
|
723
768
|
# We're making a tradeoff here between consuming more memory instead of
|
@@ -852,10 +897,11 @@ module Sidekiq
|
|
852
897
|
#
|
853
898
|
class Workers
|
854
899
|
include Enumerable
|
900
|
+
include RedisScanner
|
855
901
|
|
856
902
|
def each
|
857
903
|
Sidekiq.redis do |conn|
|
858
|
-
procs = conn
|
904
|
+
procs = sscan(conn, 'processes')
|
859
905
|
procs.sort.each do |key|
|
860
906
|
valid, workers = conn.pipelined do
|
861
907
|
conn.exists(key)
|
@@ -877,7 +923,7 @@ module Sidekiq
|
|
877
923
|
# which can easily get out of sync with crashy processes.
|
878
924
|
def size
|
879
925
|
Sidekiq.redis do |conn|
|
880
|
-
procs = conn
|
926
|
+
procs = sscan(conn, 'processes')
|
881
927
|
if procs.empty?
|
882
928
|
0
|
883
929
|
else
|