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.

Files changed (59) 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 +2 -0
  5. data/.travis.yml +6 -13
  6. data/COMM-LICENSE +11 -9
  7. data/Changes.md +136 -1
  8. data/Ent-Changes.md +46 -3
  9. data/Gemfile +14 -20
  10. data/LICENSE +1 -1
  11. data/Pro-4.0-Upgrade.md +35 -0
  12. data/Pro-Changes.md +125 -0
  13. data/README.md +5 -3
  14. data/Rakefile +2 -5
  15. data/bin/sidekiqctl +13 -92
  16. data/bin/sidekiqload +2 -2
  17. data/lib/sidekiq.rb +24 -15
  18. data/lib/sidekiq/api.rb +83 -37
  19. data/lib/sidekiq/cli.rb +106 -76
  20. data/lib/sidekiq/client.rb +36 -33
  21. data/lib/sidekiq/ctl.rb +221 -0
  22. data/lib/sidekiq/delay.rb +23 -2
  23. data/lib/sidekiq/exception_handler.rb +2 -4
  24. data/lib/sidekiq/fetch.rb +1 -1
  25. data/lib/sidekiq/job_logger.rb +4 -3
  26. data/lib/sidekiq/job_retry.rb +51 -24
  27. data/lib/sidekiq/launcher.rb +18 -12
  28. data/lib/sidekiq/logging.rb +9 -5
  29. data/lib/sidekiq/manager.rb +5 -6
  30. data/lib/sidekiq/middleware/server/active_record.rb +2 -1
  31. data/lib/sidekiq/processor.rb +85 -48
  32. data/lib/sidekiq/rails.rb +7 -0
  33. data/lib/sidekiq/redis_connection.rb +40 -4
  34. data/lib/sidekiq/scheduled.rb +35 -8
  35. data/lib/sidekiq/testing.rb +4 -4
  36. data/lib/sidekiq/util.rb +5 -1
  37. data/lib/sidekiq/version.rb +1 -1
  38. data/lib/sidekiq/web.rb +4 -4
  39. data/lib/sidekiq/web/action.rb +2 -2
  40. data/lib/sidekiq/web/application.rb +24 -2
  41. data/lib/sidekiq/web/helpers.rb +18 -8
  42. data/lib/sidekiq/web/router.rb +10 -10
  43. data/lib/sidekiq/worker.rb +39 -22
  44. data/sidekiq.gemspec +6 -17
  45. data/web/assets/javascripts/application.js +0 -0
  46. data/web/assets/javascripts/dashboard.js +15 -5
  47. data/web/assets/stylesheets/application.css +35 -2
  48. data/web/assets/stylesheets/bootstrap.css +2 -2
  49. data/web/locales/ar.yml +1 -0
  50. data/web/locales/en.yml +2 -0
  51. data/web/locales/es.yml +4 -3
  52. data/web/locales/ja.yml +5 -3
  53. data/web/views/_footer.erb +3 -0
  54. data/web/views/_nav.erb +3 -17
  55. data/web/views/layout.erb +1 -1
  56. data/web/views/queue.erb +1 -0
  57. data/web/views/queues.erb +2 -0
  58. data/web/views/retries.erb +4 -0
  59. 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://travis-ci.org/mperham/sidekiq.svg)](https://travis-ci.org/mperham/sidekiq)
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, 140 characters is not enough.**
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 :default => :test
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
- class Sidekiqctl
6
- DEFAULT_KILL_TIMEOUT = 10
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
- stage = ARGV[0]
94
- pidfile = ARGV[1]
95
- timeout = ARGV[2].to_i
96
- timeout = Sidekiqctl::DEFAULT_KILL_TIMEOUT if timeout == 0
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
- Sidekiqctl.new(stage, pidfile, timeout)
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 10 seconds for process to exit.
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'.freeze
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: 25,
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: 15,
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
- }.freeze
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 slave, need
98
- # to disconnect and reopen the socket to get back to the master.
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.default_retries_exhausted = -> (job, ex) do
173
+ # config.death_handlers << ->(job, ex) do
161
174
  # end
162
175
  # end
163
- def self.default_retries_exhausted=(prok)
164
- @default_retries_exhausted = prok
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'.freeze)
55
- conn.get('stat:failed'.freeze)
56
- conn.zcard('schedule'.freeze)
57
- conn.zcard('retry'.freeze)
58
- conn.zcard('dead'.freeze)
59
- conn.scard('processes'.freeze)
60
- conn.lrange('queue:default'.freeze, -1, -1)
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
- pipe1_res[7].each {|key| conn.hget(key, 'busy'.freeze) }
69
- pipe1_res[8].each {|queue| conn.llen("queue:#{queue}") }
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 = pipe1_res[7].size
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'.freeze] || now
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.smembers('queues'.freeze)
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".freeze)
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.smembers('queues'.freeze) }.sort.map { |q| Sidekiq::Queue.new(q) }
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".freeze, name)
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
- @args ||= case klass
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'.freeze]
376
+ if self['encrypt']
353
377
  # no point in showing 150+ bytes of random garbage
354
- args[-1] = '[encrypted data]'.freeze
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
- now = Time.now.to_f
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
- self.class.cleanup if clean_plz
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 self.cleanup
742
+ def cleanup
698
743
  count = 0
699
744
  Sidekiq.redis do |conn|
700
- procs = conn.smembers('processes').sort
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.smembers('processes') }.sort
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.smembers('processes')
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.smembers('processes')
926
+ procs = sscan(conn, 'processes')
881
927
  if procs.empty?
882
928
  0
883
929
  else