sidekiq 2.16.1 → 2.17.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 34e9d5b007bd144d33930ee67fa26a492e6664eb
4
- data.tar.gz: 28e8782a74a452e75040674eaf22ac33cf2bb660
3
+ metadata.gz: c3c94aa8a163d8572aaa7c04bc1fbdf0b2bb737c
4
+ data.tar.gz: d7cd0118de313f863b5c6ead2163a47e0cb8cdc9
5
5
  SHA512:
6
- metadata.gz: a0c318ac705b8ca596327765b1ea1ed914534b70736dc3af10c8adac268d53f576e30df7b4a56568fd8b5f97e1f4e739609af50fc03ccf83d730f1a8c9bfcfd7
7
- data.tar.gz: bc670c8eb9e5d31fe24d4d7a7ef7301e8390d606c178c6b68b9638b8588f298c63c97d500280ddf802f69b602a589ca2d913f7336338ac00a2582fecec4ae58b
6
+ metadata.gz: ce15a352e04acb9be28519faf11a2bbac4cc3deec7467abef232a53679cde91d4a60a5f08bf0143cd3ebde20559e8ee112e2ef270332e27fc8a95814eb7df9cd
7
+ data.tar.gz: 2ea6a283ea6850816178520608dd37fec6e46ebe72ce933daa02204862f1815d588a02b790b33009c39fe56ff55f90b108f9c445e36875ed8d5f4596c53c4c3a
@@ -1,8 +1,10 @@
1
1
  language: ruby
2
+ services:
3
+ - redis-server
2
4
  rvm:
3
5
  - 1.9.3
4
6
  - jruby-19mode
5
- - rbx-19mode
7
+ - rbx-2.1.1
6
8
  - 2.0.0
7
9
  branches:
8
10
  only:
@@ -15,5 +17,4 @@ notifications:
15
17
  matrix:
16
18
  allow_failures:
17
19
  - rvm: jruby-19mode
18
- - rvm: rbx-19mode
19
- - rvm: 2.0.0
20
+ - rvm: rbx-2.1.1
data/Changes.md CHANGED
@@ -1,3 +1,13 @@
1
+ 2.17.0
2
+ -----------
3
+
4
+ - Change USR1 signal handling to exit process as soon as all workers are quiet. [#1358]
5
+ - Change `Sidekiq::Client#push_bulk` to return an array of pushed `jid`s. [#1315, barelyknown]
6
+ - Web UI refactoring to use more API internally (yummy dogfood!)
7
+ - Much faster Sidekiq::Job#delete performance for larger queue sizes
8
+ - Further capistrano 3 fixes
9
+ - Many misc minor fixes
10
+
1
11
  2.16.1
2
12
  -----------
3
13
 
@@ -1,13 +1,56 @@
1
1
  Sidekiq Pro Changelog
2
2
  =======================
3
3
 
4
- Please see http://sidekiq.org/pro for more details and how to buy.
4
+ Please see [http://sidekiq.org/pro](http://sidekiq.org/pro) for more details and how to buy.
5
+
6
+ HEAD
7
+ -----------
8
+
9
+ Thanks to @jonhyman for his contributions to this Sidekiq Pro release.
10
+
11
+ This release includes new functionality based on the SCAN command newly
12
+ added to Redis 2.8. Pro still works with Redis 2.4 but some
13
+ functionality will be unavailable.
14
+
15
+ - Job Filtering in the Web UI!
16
+ You can now filter retries and scheduled jobs in the Web UI so you
17
+ only see the jobs relevant to your needs. Queues cannot be filtered;
18
+ Redis does not provide the same SCAN operation on the LIST type.
19
+ **Redis 2.8 only**
20
+ - SCAN support in the Sidekiq::SortedSet API. Here's an example that
21
+ finds all jobs which contain the substring "Warehouse::OrderShip"
22
+ and deletes all matching retries. If the set is large, this API
23
+ will be **MUCH** faster than standard iteration using each.
24
+ **Redis 2.8 only**
25
+ ```ruby
26
+ Sidekiq::RetrySet.new.scan("Warehouse::OrderShip") do |job|
27
+ job.delete
28
+ end
29
+ ```
30
+
31
+ - Sidekiq::Batch#jobs now returns the set of JIDs added to the batch.
32
+ - Sidekiq::Batch#jids returns the complete set of JIDs associated with the batch.
33
+ - Sidekiq::Batch#remove\_jobs(jid, jid, ...) removes JIDs from the set, allowing early termination of jobs if they become irrelevant according to application logic.
34
+ - Sidekiq::Batch#include?(jid) allows jobs to check if they are still
35
+ relevant to a Batch and exit early if not.
36
+ - Sidekiq::SortedSet#find\_job(jid) now uses server-side Lua **Redis 2.6 only** [jonhyman]
37
+ - The statsd integration now sets global job counts:
38
+ ```ruby
39
+ jobs.count
40
+ jobs.success
41
+ jobs.failure
42
+ ```
43
+
44
+ - Change shutdown logic to push leftover jobs in the private queue back
45
+ into the public queue when shutting down with Reliable Fetch. This
46
+ allows the safe decommission of a Sidekiq Pro process when autoscaling. [jonhyman]
47
+ - Pro now requires Sidekiq 2.17.0
5
48
 
6
49
  1.2.5
7
50
  -----------
8
51
 
9
- - Convert Batch UI to use Sidekiq 2.16's support for extension
10
- localization.
52
+ - Convert Batch UI to use Sidekiq 2.16's support for extension localization.
53
+ - Update reliable\_push to work with Sidekiq::Client refactoring in 2.16
11
54
  - Pro now requires Sidekiq 2.16.0
12
55
 
13
56
  1.2.4
@@ -195,7 +195,7 @@ module Sidekiq
195
195
  # Remove this job from the queue.
196
196
  def delete
197
197
  count = Sidekiq.redis do |conn|
198
- conn.lrem("queue:#{@queue}", 0, @value)
198
+ conn.lrem("queue:#{@queue}", 1, @value)
199
199
  end
200
200
  count != 0
201
201
  end
@@ -326,8 +326,9 @@ module Sidekiq
326
326
  end
327
327
  ns = opts.delete(:namespace)
328
328
  if ns
329
- Sidekiq.logger.warn("namespace should be set in your ruby initializer, is ignored in config file")
330
- Sidekiq.logger.warn("config.redis = { :url => ..., :namespace => '#{ns}' }")
329
+ # logger hasn't been initialized yet, puts is all we have.
330
+ puts("namespace should be set in your ruby initializer, is ignored in config file")
331
+ puts("config.redis = { :url => ..., :namespace => '#{ns}' }")
331
332
  end
332
333
  opts
333
334
  end
@@ -53,7 +53,8 @@ module Sidekiq
53
53
 
54
54
  ##
55
55
  # Push a large number of jobs to Redis. In practice this method is only
56
- # useful if you are pushing tens of thousands of jobs or more. This method
56
+ # useful if you are pushing tens of thousands of jobs or more, or if you need
57
+ # to ensure that a batch doesn't complete prematurely. This method
57
58
  # basically cuts down on the redis round trip latency.
58
59
  #
59
60
  # Takes the same arguments as #push except that args is expected to be
@@ -61,7 +62,7 @@ module Sidekiq
61
62
  # is run through the client middleware pipeline and each job gets its own Job ID
62
63
  # as normal.
63
64
  #
64
- # Returns the number of jobs pushed or nil if the pushed failed. The number of jobs
65
+ # Returns an array of the of pushed jobs' jids or nil if the pushed failed. The number of jobs
65
66
  # pushed can be less than the number given if the middleware stopped processing for one
66
67
  # or more jobs.
67
68
  def push_bulk(items)
@@ -73,7 +74,7 @@ module Sidekiq
73
74
 
74
75
  pushed = false
75
76
  pushed = raw_push(payloads) if !payloads.empty?
76
- pushed ? payloads.size : nil
77
+ pushed ? payloads.collect { |payload| payload['jid'] } : nil
77
78
  end
78
79
 
79
80
  class << self
@@ -186,6 +187,7 @@ module Sidekiq
186
187
  normalized_item = Sidekiq.default_worker_options.merge(item)
187
188
  end
188
189
 
190
+ normalized_item['queue'] = normalized_item['queue'].to_s
189
191
  normalized_item['jid'] ||= SecureRandom.hex(12)
190
192
  normalized_item['enqueued_at'] ||= Time.now.to_f
191
193
  normalized_item
@@ -41,13 +41,13 @@ module Sidekiq
41
41
  after(0) { fetch }
42
42
  end
43
43
  rescue => ex
44
- handle_exception(ex)
44
+ handle_fetch_exception(ex)
45
45
  end
46
46
 
47
47
  end
48
48
  end
49
49
 
50
- def handle_exception(ex)
50
+ def handle_fetch_exception(ex)
51
51
  if !@down
52
52
  logger.error("Error fetching message: #{ex}")
53
53
  ex.backtrace.each do |bt|
@@ -90,7 +90,9 @@ module Sidekiq
90
90
  UnitOfWork.new(*work) if work
91
91
  end
92
92
 
93
- def self.bulk_requeue(inprogress)
93
+ # By leaving this as a class method, it can be pluggable and used by the Manager actor. Making it
94
+ # an instance method will make it async to the Fetcher actor
95
+ def self.bulk_requeue(inprogress, options)
94
96
  Sidekiq.logger.debug { "Re-queueing terminated jobs" }
95
97
  jobs_to_requeue = {}
96
98
  inprogress.each do |unit_of_work|
@@ -19,8 +19,11 @@ module Sidekiq
19
19
  attr_reader :busy
20
20
  attr_accessor :fetcher
21
21
 
22
+ SPIN_TIME_FOR_GRACEFUL_SHUTDOWN = 1
23
+
22
24
  def initialize(options={})
23
25
  logger.debug { options.inspect }
26
+ @options = options
24
27
  @count = options[:concurrency] || 25
25
28
  @done_callback = nil
26
29
 
@@ -37,7 +40,7 @@ module Sidekiq
37
40
 
38
41
  def stop(options={})
39
42
  watchdog('Manager#stop died') do
40
- shutdown = options[:shutdown]
43
+ should_shutdown = options[:shutdown]
41
44
  timeout = options[:timeout]
42
45
 
43
46
  @done = true
@@ -47,10 +50,20 @@ module Sidekiq
47
50
  @ready.clear
48
51
 
49
52
  clear_worker_set
53
+ return if clean_up_for_graceful_shutdown
54
+
55
+ hard_shutdown_in timeout if should_shutdown
56
+ end
57
+ end
50
58
 
51
- return after(0) { signal(:shutdown) } if @busy.empty?
52
- hard_shutdown_in timeout if shutdown
59
+ def clean_up_for_graceful_shutdown
60
+ if @busy.empty?
61
+ shutdown
62
+ return true
53
63
  end
64
+
65
+ after(SPIN_TIME_FOR_GRACEFUL_SHUTDOWN) { clean_up_for_graceful_shutdown }
66
+ false
54
67
  end
55
68
 
56
69
  def start
@@ -69,7 +82,7 @@ module Sidekiq
69
82
  @busy.delete(processor)
70
83
  if stopped?
71
84
  processor.terminate if processor.alive?
72
- signal(:shutdown) if @busy.empty?
85
+ shutdown if @busy.empty?
73
86
  else
74
87
  @ready << processor if processor.alive?
75
88
  end
@@ -89,7 +102,7 @@ module Sidekiq
89
102
  @ready << p
90
103
  dispatch
91
104
  else
92
- signal(:shutdown) if @busy.empty?
105
+ shutdown if @busy.empty?
93
106
  end
94
107
  end
95
108
  end
@@ -151,22 +164,16 @@ module Sidekiq
151
164
  # They must die but their messages shall live on.
152
165
  logger.info("Still waiting for #{@busy.size} busy workers")
153
166
 
154
- # Re-enqueue terminated jobs
155
- # NOTE: You may notice that we may push a job back to redis before
156
- # the worker thread is terminated. This is ok because Sidekiq's
157
- # contract says that jobs are run AT LEAST once. Process termination
158
- # is delayed until we're certain the jobs are back in Redis because
159
- # it is worse to lose a job than to run it twice.
160
- Sidekiq::Fetcher.strategy.bulk_requeue(@in_progress.values)
167
+ requeue
161
168
 
162
- logger.debug { "Terminating #{@busy.size} busy worker threads" }
169
+ logger.warn { "Terminating #{@busy.size} busy worker threads" }
163
170
  @busy.each do |processor|
164
171
  if processor.alive? && t = @threads.delete(processor.object_id)
165
172
  t.raise Shutdown
166
173
  end
167
174
  end
168
175
 
169
- after(0) { signal(:shutdown) }
176
+ signal_shutdown
170
177
  end
171
178
  end
172
179
  end
@@ -184,5 +191,25 @@ module Sidekiq
184
191
  def stopped?
185
192
  @done
186
193
  end
194
+
195
+ def shutdown
196
+ requeue
197
+ signal_shutdown
198
+ end
199
+
200
+ def signal_shutdown
201
+ after(0) { signal(:shutdown) }
202
+ end
203
+
204
+ def requeue
205
+ # Re-enqueue terminated jobs
206
+ # NOTE: You may notice that we may push a job back to redis before
207
+ # the worker thread is terminated. This is ok because Sidekiq's
208
+ # contract says that jobs are run AT LEAST once. Process termination
209
+ # is delayed until we're certain the jobs are back in Redis because
210
+ # it is worse to lose a job than to run it twice.
211
+ Sidekiq::Fetcher.strategy.bulk_requeue(@in_progress.values, @options)
212
+ @in_progress.clear
213
+ end
187
214
  end
188
215
  end
@@ -49,13 +49,16 @@ module Sidekiq
49
49
  # end
50
50
  # end
51
51
  #
52
- # This is an example of a minimal client middleware:
52
+ # This is an example of a minimal client middleware, note
53
+ # the method must return the result or the job will not push
54
+ # to Redis:
53
55
  #
54
56
  # class MyClientHook
55
57
  # def call(worker_class, msg, queue)
56
58
  # puts "Before push"
57
- # yield
59
+ # result = yield
58
60
  # puts "After push"
61
+ # result
59
62
  # end
60
63
  # end
61
64
  #
@@ -37,6 +37,7 @@ module Sidekiq
37
37
  do_defer do
38
38
  @boss.async.real_thread(proxy_id, Thread.current)
39
39
 
40
+ ack = true
40
41
  begin
41
42
  msg = Sidekiq.load_json(msgstr)
42
43
  klass = msg['class'].constantize
@@ -50,12 +51,14 @@ module Sidekiq
50
51
  end
51
52
  rescue Sidekiq::Shutdown
52
53
  # Had to force kill this job because it didn't finish
53
- # within the timeout.
54
+ # within the timeout. Don't acknowledge the work since
55
+ # we didn't properly finish it.
56
+ ack = false
54
57
  rescue Exception => ex
55
58
  handle_exception(ex, msg || { :message => msgstr })
56
59
  raise
57
60
  ensure
58
- work.acknowledge
61
+ work.acknowledge if ack
59
62
  end
60
63
  end
61
64
 
@@ -1,5 +1,6 @@
1
1
  require 'connection_pool'
2
2
  require 'redis'
3
+ require 'uri'
3
4
 
4
5
  module Sidekiq
5
6
  class RedisConnection
@@ -10,7 +11,7 @@ module Sidekiq
10
11
  if url
11
12
  options[:url] = url
12
13
  end
13
-
14
+
14
15
  # need a connection for Fetcher and Retry
15
16
  size = options[:size] || (Sidekiq.server? ? (Sidekiq.options[:concurrency] + 2) : 5)
16
17
  pool_timeout = options[:pool_timeout] || 1
@@ -53,18 +54,23 @@ module Sidekiq
53
54
  end
54
55
 
55
56
  def log_info(options)
57
+ # Don't log Redis AUTH password
58
+ scrubbed_options = options.dup
59
+ if scrubbed_options[:url] && (uri = URI.parse(scrubbed_options[:url])) && uri.password
60
+ uri.password = "REDACTED"
61
+ scrubbed_options[:url] = uri.to_s
62
+ end
56
63
  if Sidekiq.server?
57
- Sidekiq.logger.info("Booting Sidekiq #{Sidekiq::VERSION} with redis options #{options}")
64
+ Sidekiq.logger.info("Booting Sidekiq #{Sidekiq::VERSION} with redis options #{scrubbed_options}")
58
65
  else
59
- Sidekiq.logger.info("#{Sidekiq::NAME} client with redis options #{options}")
66
+ Sidekiq.logger.info("#{Sidekiq::NAME} client with redis options #{scrubbed_options}")
60
67
  end
61
68
  end
62
69
 
63
70
  def determine_redis_provider
64
71
  # REDISTOGO_URL is only support for legacy reasons
65
- return ENV['REDISTOGO_URL'] if ENV['REDISTOGO_URL']
66
72
  provider = ENV['REDIS_PROVIDER'] || 'REDIS_URL'
67
- ENV[provider]
73
+ ENV[provider] || ENV['REDISTOGO_URL']
68
74
  end
69
75
 
70
76
  end
@@ -23,6 +23,12 @@ namespace :load do
23
23
  end
24
24
  end
25
25
 
26
+ namespace :deploy do
27
+ before :starting, :check_sidekiq_hooks do
28
+ invoke 'sidekiq:add_default_hooks' if fetch(:sidekiq_default_hooks)
29
+ end
30
+ end
31
+
26
32
  namespace :sidekiq do
27
33
  def for_each_process(&block)
28
34
  fetch(:sidekiq_processes).times do |idx|
@@ -30,6 +36,13 @@ namespace :sidekiq do
30
36
  end
31
37
  end
32
38
 
39
+ task :add_default_hooks do
40
+ after 'deploy:starting', 'sidekiq:quiet'
41
+ after 'deploy:updated', 'sidekiq:stop'
42
+ after 'deploy:reverted', 'sidekiq:stop'
43
+ after 'deploy:published', 'sidekiq:start'
44
+ end
45
+
33
46
  desc "Quiet sidekiq (stop accepting new work)"
34
47
  task :quiet do
35
48
  on roles fetch(:sidekiq_role) do
@@ -86,11 +99,4 @@ namespace :sidekiq do
86
99
  invoke 'sidekiq:start'
87
100
  end
88
101
 
89
- if fetch(:sidekiq_default_hooks)
90
- after 'deploy:starting', 'sidekiq:quiet'
91
- after 'deploy:updated', 'sidekiq:stop'
92
- after 'deploy:reverted', 'sidekiq:stop'
93
- after 'deploy:published', 'sidekiq:start'
94
- end
95
-
96
102
  end
@@ -1,3 +1,3 @@
1
1
  module Sidekiq
2
- VERSION = "2.16.1"
2
+ VERSION = "2.17.0"
3
3
  end
@@ -73,7 +73,7 @@ module Sidekiq
73
73
  get '/retries' do
74
74
  @count = (params[:count] || 25).to_i
75
75
  (@current_page, @total_size, @retries) = page("retry", params[:page], @count)
76
- @retries = @retries.map {|msg, score| [Sidekiq.load_json(msg), score] }
76
+ @retries = @retries.map {|msg, score| Sidekiq::SortedEntry.new(nil, score, msg) }
77
77
  erb :retries
78
78
  end
79
79
 
@@ -125,7 +125,7 @@ module Sidekiq
125
125
  get '/scheduled' do
126
126
  @count = (params[:count] || 25).to_i
127
127
  (@current_page, @total_size, @scheduled) = page("schedule", params[:page], @count)
128
- @scheduled = @scheduled.map {|msg, score| [Sidekiq.load_json(msg), score] }
128
+ @scheduled = @scheduled.map {|msg, score| Sidekiq::SortedEntry.new(nil, score, msg) }
129
129
  erb :scheduled
130
130
  end
131
131
 
@@ -16,6 +16,10 @@ module Sidekiq
16
16
  end
17
17
  end
18
18
 
19
+ # This is a hook for a Sidekiq Pro feature. Please don't touch.
20
+ def filtering(*)
21
+ end
22
+
19
23
  def locale
20
24
  lang = (request.env["HTTP_ACCEPT_LANGUAGE"] || 'en')[0,2]
21
25
  strings[lang] ? lang : 'en'
@@ -159,7 +163,11 @@ module Sidekiq
159
163
  end
160
164
 
161
165
  def h(text)
162
- Rack::Utils.escape_html(text)
166
+ ::Rack::Utils.escape_html(text)
167
+ rescue ArgumentError => e
168
+ raise unless e.message.eql?('invalid byte sequence in UTF-8')
169
+ text.encode!('UTF-16', 'UTF-8', invalid: :replace, replace: '').encode!('UTF-8', 'UTF-16')
170
+ retry
163
171
  end
164
172
 
165
173
  # Any paginated list that performs an action needs to redirect
@@ -3,7 +3,6 @@
3
3
  :require: ./test/fake_env.rb
4
4
  :pidfile: /tmp/sidekiq-config-test.pid
5
5
  :logfile: /tmp/sidekiq.log
6
- :namespace: sidekiq
7
6
  :concurrency: 50
8
7
  :queues:
9
8
  - [<%="very_"%>often, 2]
@@ -168,12 +168,17 @@ class TestClient < Sidekiq::Test
168
168
  Sidekiq::Queue.new.clear
169
169
  end
170
170
  it 'can push a large set of jobs at once' do
171
- count = Sidekiq::Client.push_bulk('class' => QueuedWorker, 'args' => (1..1_000).to_a.map { |x| Array(x) })
172
- assert_equal 1_000, count
171
+ jids = Sidekiq::Client.push_bulk('class' => QueuedWorker, 'args' => (1..1_000).to_a.map { |x| Array(x) })
172
+ assert_equal 1_000, jids.size
173
173
  end
174
174
  it 'can push a large set of jobs at once using a String class' do
175
- count = Sidekiq::Client.push_bulk('class' => 'QueuedWorker', 'args' => (1..1_000).to_a.map { |x| Array(x) })
176
- assert_equal 1_000, count
175
+ jids = Sidekiq::Client.push_bulk('class' => 'QueuedWorker', 'args' => (1..1_000).to_a.map { |x| Array(x) })
176
+ assert_equal 1_000, jids.size
177
+ end
178
+ it 'returns the jids for the jobs' do
179
+ Sidekiq::Client.push_bulk('class' => 'QueuedWorker', 'args' => (1..2).to_a.map { |x| Array(x) }).each do |jid|
180
+ assert_match /[0-9a-f]{12}/, jid
181
+ end
177
182
  end
178
183
  end
179
184
 
@@ -203,7 +208,9 @@ class TestClient < Sidekiq::Test
203
208
  begin
204
209
  assert_equal nil, Sidekiq::Client.push('class' => MyWorker, 'args' => [0])
205
210
  assert_match /[0-9a-f]{12}/, Sidekiq::Client.push('class' => MyWorker, 'args' => [1])
206
- assert_equal 1, Sidekiq::Client.push_bulk('class' => MyWorker, 'args' => [[0], [1]])
211
+ Sidekiq::Client.push_bulk('class' => MyWorker, 'args' => [[0], [1]]).each do |jid|
212
+ assert_match /[0-9a-f]{12}/, jid
213
+ end
207
214
  ensure
208
215
  Sidekiq.client_middleware.remove Stopper
209
216
  end
@@ -36,7 +36,7 @@ class TestFetcher < Sidekiq::Test
36
36
  assert_equal 0, q1.size
37
37
  assert_equal 0, q2.size
38
38
  uow = Sidekiq::BasicFetch::UnitOfWork
39
- Sidekiq::BasicFetch.bulk_requeue([uow.new('fuzzy:queue:foo', 'bob'), uow.new('fuzzy:queue:foo', 'bar'), uow.new('fuzzy:queue:bar', 'widget')])
39
+ Sidekiq::BasicFetch.bulk_requeue([uow.new('fuzzy:queue:foo', 'bob'), uow.new('fuzzy:queue:foo', 'bar'), uow.new('fuzzy:queue:bar', 'widget')], {:queues => []})
40
40
  assert_equal 2, q1.size
41
41
  assert_equal 1, q2.size
42
42
  end
@@ -29,6 +29,7 @@ class TestManager < Sidekiq::Test
29
29
  uow.expect(:requeue, nil, [])
30
30
 
31
31
  mgr = Sidekiq::Manager.new(options)
32
+ mgr.fetcher = Sidekiq::BasicFetch.new({:queues => []})
32
33
  mgr.stop
33
34
  mgr.assign(uow)
34
35
  uow.verify
@@ -36,6 +37,7 @@ class TestManager < Sidekiq::Test
36
37
 
37
38
  it 'shuts down the system' do
38
39
  mgr = Sidekiq::Manager.new(options)
40
+ mgr.fetcher = Sidekiq::BasicFetch.new({:queues => []})
39
41
  mgr.stop
40
42
 
41
43
  assert mgr.busy.empty?
@@ -82,7 +82,7 @@ class TestMiddleware < Sidekiq::Test
82
82
  processor = Sidekiq::Processor.new(boss)
83
83
  actor = Minitest::Mock.new
84
84
  actor.expect(:processor_done, nil, [processor])
85
- actor.expect(:real_thread, nil, [nil, Celluloid::Thread])
85
+ actor.expect(:real_thread, nil, [nil, Thread])
86
86
  boss.expect(:async, actor, [])
87
87
  boss.expect(:async, actor, [])
88
88
  processor.process(Sidekiq::BasicFetch::UnitOfWork.new('queue:default', msg))
@@ -31,7 +31,7 @@ class TestProcessor < Sidekiq::Test
31
31
  msg = Sidekiq.dump_json({ 'class' => MockWorker.to_s, 'args' => ['myarg'] })
32
32
  actor = Minitest::Mock.new
33
33
  actor.expect(:processor_done, nil, [@processor])
34
- actor.expect(:real_thread, nil, [nil, Celluloid::Thread])
34
+ actor.expect(:real_thread, nil, [nil, Thread])
35
35
  @boss.expect(:async, actor, [])
36
36
  @boss.expect(:async, actor, [])
37
37
  @processor.process(work(msg))
@@ -41,7 +41,7 @@ class TestProcessor < Sidekiq::Test
41
41
 
42
42
  it 'passes exceptions to ExceptionHandler' do
43
43
  actor = Minitest::Mock.new
44
- actor.expect(:real_thread, nil, [nil, Celluloid::Thread])
44
+ actor.expect(:real_thread, nil, [nil, Thread])
45
45
  @boss.expect(:async, actor, [])
46
46
  msg = Sidekiq.dump_json({ 'class' => MockWorker.to_s, 'args' => ['boom'] })
47
47
  begin
@@ -57,7 +57,7 @@ class TestProcessor < Sidekiq::Test
57
57
  msg = Sidekiq.dump_json({ 'class' => MockWorker.to_s, 'args' => ['boom'] })
58
58
  re_raise = false
59
59
  actor = Minitest::Mock.new
60
- actor.expect(:real_thread, nil, [nil, Celluloid::Thread])
60
+ actor.expect(:real_thread, nil, [nil, Thread])
61
61
  @boss.expect(:async, actor, [])
62
62
 
63
63
  begin
@@ -75,7 +75,7 @@ class TestProcessor < Sidekiq::Test
75
75
  processor = ::Sidekiq::Processor.new(@boss)
76
76
  actor = Minitest::Mock.new
77
77
  actor.expect(:processor_done, nil, [processor])
78
- actor.expect(:real_thread, nil, [nil, Celluloid::Thread])
78
+ actor.expect(:real_thread, nil, [nil, Thread])
79
79
  @boss.expect(:async, actor, [])
80
80
  @boss.expect(:async, actor, [])
81
81
  processor.process(work(msgstr))
@@ -103,7 +103,7 @@ class TestProcessor < Sidekiq::Test
103
103
  def successful_job
104
104
  msg = Sidekiq.dump_json({ 'class' => MockWorker.to_s, 'args' => ['myarg'] })
105
105
  actor = Minitest::Mock.new
106
- actor.expect(:real_thread, nil, [nil, Celluloid::Thread])
106
+ actor.expect(:real_thread, nil, [nil, Thread])
107
107
  actor.expect(:processor_done, nil, [@processor])
108
108
  @boss.expect(:async, actor, [])
109
109
  @boss.expect(:async, actor, [])
@@ -131,7 +131,7 @@ class TestProcessor < Sidekiq::Test
131
131
 
132
132
  def failed_job
133
133
  actor = Minitest::Mock.new
134
- actor.expect(:real_thread, nil, [nil, Celluloid::Thread])
134
+ actor.expect(:real_thread, nil, [nil, Thread])
135
135
  @boss.expect(:async, actor, [])
136
136
  msg = Sidekiq.dump_json({ 'class' => MockWorker.to_s, 'args' => ['boom'] })
137
137
  begin
@@ -87,6 +87,20 @@ class TestRedisConnection < Sidekiq::Test
87
87
  end
88
88
  end
89
89
 
90
+ describe "with REDISTOGO_URL and a parallel REDIS_PROVIDER set" do
91
+ it "sets connection URI to the provider" do
92
+ uri = 'redis://sidekiq-redis-provider:6379/0'
93
+ provider = 'SIDEKIQ_REDIS_PROVIDER'
94
+
95
+ ENV['REDIS_PROVIDER'] = provider
96
+ ENV[provider] = uri
97
+ ENV['REDISTOGO_URL'] = 'redis://redis-to-go:6379/0'
98
+ with_env_var provider, uri, true
99
+
100
+ ENV[provider] = nil
101
+ end
102
+ end
103
+
90
104
  describe "with REDIS_PROVIDER set" do
91
105
  it "sets connection URI to the provider" do
92
106
  uri = 'redis://sidekiq-redis-provider:6379/0'
@@ -31,7 +31,7 @@ class TestScheduling < Sidekiq::Test
31
31
  end
32
32
 
33
33
  it 'schedules job right away on negative timestamp/interval' do
34
- @redis.expect :sadd, true, ['queues', :custom_queue]
34
+ @redis.expect :sadd, true, ['queues', 'custom_queue']
35
35
  @redis.expect :lpush, true, ['queue:custom_queue', Array]
36
36
  assert ScheduledWorker.perform_in(-300, 'mike')
37
37
  @redis.verify
@@ -188,6 +188,17 @@ td form {
188
188
  margin-bottom: 0;
189
189
  }
190
190
 
191
+ td.table-checkbox {
192
+ padding: 0px;
193
+ }
194
+
195
+ td.table-checkbox label {
196
+ height: 100%;
197
+ width: 100%;
198
+ padding: 8px;
199
+ margin-bottom: 0;
200
+ }
201
+
191
202
  .navbar .navbar-brand {
192
203
  color: #b1003e;
193
204
  padding: 13px;
@@ -2,11 +2,12 @@
2
2
  <div class="col-sm-5">
3
3
  <h3><%= t('Retries') %></h3>
4
4
  </div>
5
- <div class="col-sm-4">
6
- <% if @retries.size > 0 %>
5
+ <% if @retries.size > 0 && @total_size > @count %>
6
+ <div class="col-sm-4">
7
7
  <%= erb :_paging, :locals => { :url => "#{root_path}retries" } %>
8
- <% end %>
9
- </div>
8
+ </div>
9
+ <% end %>
10
+ <%= filtering('retries') %>
10
11
  </header>
11
12
 
12
13
  <% if @retries.size > 0 %>
@@ -25,24 +26,26 @@
25
26
  <th><%= t('Error') %></th>
26
27
  </tr>
27
28
  </thead>
28
- <% @retries.each do |msg, score| %>
29
+ <% @retries.each do |entry| %>
29
30
  <tr>
30
- <td>
31
- <input type='checkbox' name='key[]' value='<%= job_params(msg, score) %>' />
31
+ <td class="table-checkbox">
32
+ <label>
33
+ <input type='checkbox' name='key[]' value='<%= job_params(entry.item, entry.score) %>' />
34
+ </label>
32
35
  </td>
33
36
  <td>
34
- <a href="<%= root_path %>retries/<%= job_params(msg, score) %>"><%= relative_time(Time.at(score)) %></a>
37
+ <a href="<%= root_path %>retries/<%= job_params(entry.item, entry.score) %>"><%= relative_time(entry.at) %></a>
35
38
  </td>
36
- <td><%= msg['retry_count'] %></td>
39
+ <td><%= entry['retry_count'] %></td>
37
40
  <td>
38
- <a href="<%= root_path %>queues/<%= msg['queue'] %>"><%= msg['queue'] %></a>
41
+ <a href="<%= root_path %>queues/<%= entry.queue %>"><%= entry.queue %></a>
39
42
  </td>
40
- <td><%= msg['class'] %></td>
43
+ <td><%= entry.klass %></td>
41
44
  <td>
42
- <div class="args"><%= display_args(msg['args']) %></div>
45
+ <div class="args"><%= display_args(entry.args) %></div>
43
46
  </td>
44
47
  <td>
45
- <div><%= h truncate("#{msg['error_class']}: #{msg['error_message']}", 200) %></div>
48
+ <div><%= h truncate("#{entry['error_class']}: #{entry['error_message']}", 200) %></div>
46
49
  </td>
47
50
  </tr>
48
51
  <% end %>
@@ -2,11 +2,12 @@
2
2
  <div class="col-sm-5">
3
3
  <h3><%= t('ScheduledJobs') %></h3>
4
4
  </div>
5
- <div class="col-sm-4">
6
- <% if @scheduled.size > 0 %>
5
+ <% if @scheduled.size > 0 && @total_size > @count %>
6
+ <div class="col-sm-4">
7
7
  <%= erb :_paging, :locals => { :url => "#{root_path}scheduled" } %>
8
- <% end %>
9
- </div>
8
+ </div>
9
+ <% end %>
10
+ <%= filtering('scheduled') %>
10
11
  </header>
11
12
 
12
13
  <% if @scheduled.size > 0 %>
@@ -24,20 +25,20 @@
24
25
  <th><%= t('Arguments') %></th>
25
26
  </tr>
26
27
  </thead>
27
- <% @scheduled.each do |msg, score| %>
28
+ <% @scheduled.each do |entry| %>
28
29
  <tr>
29
30
  <td>
30
- <input type='checkbox' name='key[]' value='<%= job_params(msg, score) %>' />
31
+ <input type='checkbox' name='key[]' value='<%= job_params(entry.item, entry.score) %>' />
31
32
  </td>
32
33
  <td>
33
- <a href="<%= root_path %>scheduled/<%= job_params(msg, score) %>"><%= relative_time(Time.at(score)) %></a>
34
+ <a href="<%= root_path %>scheduled/<%= job_params(entry.item, entry.score) %>"><%= relative_time(entry.at) %></a>
34
35
  </td>
35
36
  <td>
36
- <a href="<%= root_path %>queues/<%= msg['queue'] %>"><%= msg['queue'] %></a>
37
+ <a href="<%= root_path %>queues/<%= entry.queue %>"><%= entry.queue %></a>
37
38
  </td>
38
- <td><%= msg['class'] %></td>
39
+ <td><%= entry.klass %></td>
39
40
  <td>
40
- <div class="args"><%= display_args(msg['args']) %></div>
41
+ <div class="args"><%= display_args(entry.args) %></div>
41
42
  </td>
42
43
  </tr>
43
44
  <% end %>
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sidekiq
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.16.1
4
+ version: 2.17.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mike Perham
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-10-31 00:00:00.000000000 Z
11
+ date: 2013-11-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: redis
@@ -352,7 +352,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
352
352
  version: '0'
353
353
  requirements: []
354
354
  rubyforge_project:
355
- rubygems_version: 2.0.3
355
+ rubygems_version: 2.1.9
356
356
  signing_key:
357
357
  specification_version: 4
358
358
  summary: Simple, efficient background processing for Ruby