sidekiq 2.12.4 → 2.13.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.

data/Changes.md CHANGED
@@ -1,3 +1,27 @@
1
+ 2.13.0
2
+ -----------
3
+ - Adding button to move scheduled job to main queue [guiceolin, #1020]
4
+ - fix i18n support resetting saved locale when job is retried [#1011]
5
+ - log rotation via USR2 now closes the old logger [#1008]
6
+ - Add ability to customize retry schedule, like so [jmazzi, #1027]
7
+
8
+ ```ruby
9
+ class MyWorker
10
+ include Sidekiq::Worker
11
+ sidekiq_retry_in { |count| count * 2 }
12
+ end
13
+ ```
14
+ - Redesign Worker#retries\_exhausted callback to use same form as above [jmazzi, #1030]
15
+
16
+ ```ruby
17
+ class MyWorker
18
+ include Sidekiq::Worker
19
+ sidekiq_retries_exhausted do |msg|
20
+ Rails.logger.error "Failed to process #{msg['class']} with args: #{msg['args']}"
21
+ end
22
+ end
23
+ ```
24
+
1
25
  2.12.4
2
26
  -----------
3
27
 
data/README.md CHANGED
@@ -4,16 +4,16 @@ Sidekiq
4
4
  [![Gem Version](https://badge.fury.io/rb/sidekiq.png)](https://rubygems.org/gems/sidekiq) [![Code Climate](https://codeclimate.com/github/mperham/sidekiq.png)](https://codeclimate.com/github/mperham/sidekiq) [![Build Status](https://travis-ci.org/mperham/sidekiq.png)](https://travis-ci.org/mperham/sidekiq) [![Coverage Status](https://coveralls.io/repos/mperham/sidekiq/badge.png?branch=master)](https://coveralls.io/r/mperham/sidekiq)
5
5
 
6
6
 
7
- Simple, efficient message processing for Ruby.
7
+ Simple, efficient background processing for Ruby.
8
8
 
9
- Sidekiq uses threads to handle many messages at the same time in the
9
+ Sidekiq uses threads to handle many jobs at the same time in the
10
10
  same process. It does not require Rails but will integrate tightly with
11
- Rails 3 to make background message processing dead simple.
11
+ Rails 3 to make background processing dead simple.
12
12
 
13
13
  Sidekiq is compatible with Resque. It uses the exact same
14
14
  message format as Resque so it can integrate into an existing Resque processing farm.
15
15
  You can have Sidekiq and Resque run side-by-side at the same time and
16
- use the Resque client to enqueue messages in Redis to be processed by Sidekiq.
16
+ use the Resque client to enqueue jobs in Redis to be processed by Sidekiq.
17
17
 
18
18
  At the same time, Sidekiq uses multithreading so it is much more memory efficient than
19
19
  Resque (which forks a new process for every job). You'll find that you might need
@@ -139,7 +139,7 @@ module Sidekiq
139
139
  def clear
140
140
  Sidekiq.redis do |conn|
141
141
  conn.multi do
142
- conn.del("queue:#{name}")
142
+ conn.del(@rname)
143
143
  conn.srem("queues", name)
144
144
  end
145
145
  end
@@ -222,6 +222,17 @@ module Sidekiq
222
222
  @parent.schedule(at, item)
223
223
  end
224
224
 
225
+ def add_to_queue
226
+ Sidekiq.redis do |conn|
227
+ results = conn.zrangebyscore('schedule', score, score)
228
+ conn.zremrangebyscore('schedule', score, score)
229
+ results.map do |message|
230
+ msg = Sidekiq.load_json(message)
231
+ Sidekiq::Client.push(msg)
232
+ end
233
+ end
234
+ end
235
+
225
236
  def retry
226
237
  raise "Retry not available on jobs not in the Retry queue." unless item["failed_at"]
227
238
  Sidekiq.redis do |conn|
@@ -26,9 +26,11 @@ module Sidekiq
26
26
  end
27
27
 
28
28
  def self.initialize_logger(log_target = STDOUT)
29
+ oldlogger = @logger
29
30
  @logger = Logger.new(log_target)
30
31
  @logger.level = Logger::INFO
31
32
  @logger.formatter = Pretty.new
33
+ oldlogger.close if oldlogger && !$TESTING # don't want to close testing's STDOUT logging
32
34
  @logger
33
35
  end
34
36
 
@@ -3,7 +3,7 @@ module Sidekiq::Middleware::I18n
3
3
  # to be sent to Sidekiq.
4
4
  class Client
5
5
  def call(worker_class, msg, queue)
6
- msg['locale'] = I18n.locale
6
+ msg['locale'] ||= I18n.locale
7
7
  yield
8
8
  end
9
9
  end
@@ -78,7 +78,7 @@ module Sidekiq
78
78
  end
79
79
 
80
80
  if count < max_retry_attempts
81
- delay = seconds_to_delay(count)
81
+ delay = delay_for(worker, count)
82
82
  logger.debug { "Failure! Retry #{count} in #{delay} seconds" }
83
83
  retry_at = Time.now.to_f + delay
84
84
  payload = Sidekiq.dump_json(msg)
@@ -95,7 +95,12 @@ module Sidekiq
95
95
 
96
96
  def retries_exhausted(worker, msg)
97
97
  logger.debug { "Dropping message after hitting the retry maximum: #{msg}" }
98
- worker.retries_exhausted(*msg['args']) if worker.respond_to?(:retries_exhausted)
98
+ if worker.respond_to?(:retries_exhausted)
99
+ logger.warn { "Defining #{worker.class.name}#retries_exhausted as a method is deprecated, use `sidekiq_retries_exhausted` callback instead http://git.io/Ijju8g" }
100
+ worker.retries_exhausted(*msg['args'])
101
+ elsif worker.sidekiq_retries_exhausted_block?
102
+ worker.sidekiq_retries_exhausted_block.call(msg)
103
+ end
99
104
 
100
105
  rescue Exception => e
101
106
  handle_exception(e, "Error calling retries_exhausted")
@@ -109,11 +114,24 @@ module Sidekiq
109
114
  end
110
115
  end
111
116
 
117
+ def delay_for(worker, count)
118
+ worker.sidekiq_retry_in_block? && retry_in(worker, count) || seconds_to_delay(count)
119
+ end
120
+
112
121
  # delayed_job uses the same basic formula
113
122
  def seconds_to_delay(count)
114
123
  (count ** 4) + 15 + (rand(30)*(count+1))
115
124
  end
116
125
 
126
+ def retry_in(worker, count)
127
+ begin
128
+ worker.sidekiq_retry_in_block.call(count)
129
+ rescue Exception => e
130
+ logger.error { "Failure scheduling retry using the defined `sidekiq_retry_in` in #{worker.class.name}, falling back to default: #{e.message}"}
131
+ nil
132
+ end
133
+ end
134
+
117
135
  end
118
136
  end
119
137
  end
@@ -86,7 +86,9 @@ module Sidekiq
86
86
  # Drain and run all jobs for this worker
87
87
  def drain
88
88
  while job = jobs.shift do
89
- new.perform(*job['args'])
89
+ worker = new
90
+ worker.jid = job['jid']
91
+ worker.perform(*job['args'])
90
92
  end
91
93
  end
92
94
 
@@ -94,7 +96,9 @@ module Sidekiq
94
96
  def perform_one
95
97
  raise(EmptyQueueError, "perform_one called with empty job queue") if jobs.empty?
96
98
  job = jobs.shift
97
- new.perform(*job['args'])
99
+ worker = new
100
+ worker.jid = job['jid']
101
+ worker.perform(*job['args'])
98
102
  end
99
103
  end
100
104
 
@@ -26,7 +26,7 @@ module Sidekiq
26
26
  end
27
27
 
28
28
  def process_id
29
- Process.pid
29
+ @@process_id ||= SecureRandom.hex
30
30
  end
31
31
 
32
32
  def hostname
@@ -1,3 +1,3 @@
1
1
  module Sidekiq
2
- VERSION = "2.12.4"
2
+ VERSION = "2.13.0"
3
3
  end
@@ -41,7 +41,13 @@ module Sidekiq
41
41
  def reset_worker_list
42
42
  Sidekiq.redis do |conn|
43
43
  workers = conn.smembers('workers')
44
- conn.srem('workers', *workers)
44
+ conn.srem('workers', workers) if !workers.empty?
45
+ end
46
+ end
47
+
48
+ def workers_size
49
+ Sidekiq.redis do |conn|
50
+ conn.scard('workers')
45
51
  end
46
52
  end
47
53
 
@@ -84,7 +90,7 @@ module Sidekiq
84
90
  end
85
91
 
86
92
  def current_status
87
- return 'idle' if workers.size == 0
93
+ return 'idle' if workers_size == 0
88
94
  return 'active'
89
95
  end
90
96
 
@@ -245,9 +251,14 @@ module Sidekiq
245
251
 
246
252
  post '/scheduled' do
247
253
  halt 404 unless params['key']
248
- halt 404 unless params['delete']
254
+
249
255
  params['key'].each do |key|
250
- Sidekiq::ScheduledSet.new.fetch(*parse_params(key)).first.delete
256
+ job = Sidekiq::ScheduledSet.new.fetch(*parse_params(key)).first
257
+ if params['delete']
258
+ job.delete
259
+ elsif params['add_to_queue']
260
+ job.add_to_queue
261
+ end
251
262
  end
252
263
  redirect "#{root_path}scheduled"
253
264
  end
@@ -269,7 +280,7 @@ module Sidekiq
269
280
  sidekiq: {
270
281
  processed: sidekiq_stats.processed,
271
282
  failed: sidekiq_stats.failed,
272
- busy: workers.size,
283
+ busy: workers_size,
273
284
  enqueued: sidekiq_stats.enqueued,
274
285
  scheduled: sidekiq_stats.scheduled_size,
275
286
  retries: sidekiq_stats.retry_size,
@@ -285,4 +296,3 @@ module Sidekiq
285
296
  end
286
297
 
287
298
  end
288
-
@@ -26,6 +26,8 @@ module Sidekiq
26
26
  def self.included(base)
27
27
  base.extend(ClassMethods)
28
28
  base.class_attribute :sidekiq_options_hash
29
+ base.class_attribute :sidekiq_retry_in_block
30
+ base.class_attribute :sidekiq_retries_exhausted_block
29
31
  end
30
32
 
31
33
  def logger
@@ -40,8 +42,15 @@ module Sidekiq
40
42
 
41
43
  def perform_in(interval, *args)
42
44
  int = interval.to_f
43
- ts = (int < 1_000_000_000 ? Time.now.to_f + int : int)
44
- client_push('class' => self, 'args' => args, 'at' => ts)
45
+ now = Time.now.to_f
46
+ ts = (int < 1_000_000_000 ? now + int : int)
47
+
48
+ # Optimization to enqueue something now that is scheduled to go out now or in the past
49
+ if ts <= now
50
+ perform_async(*args)
51
+ else
52
+ client_push('class' => self, 'args' => args, 'at' => ts)
53
+ end
45
54
  end
46
55
  alias_method :perform_at, :perform_in
47
56
 
@@ -58,6 +67,14 @@ module Sidekiq
58
67
  ::Sidekiq.logger.warn("#{self.name} - :timeout is unsafe and support has been removed from Sidekiq, see http://bit.ly/OtYpK for details") if opts.include? :timeout
59
68
  end
60
69
 
70
+ def sidekiq_retry_in(&block)
71
+ self.sidekiq_retry_in_block = block
72
+ end
73
+
74
+ def sidekiq_retries_exhausted(&block)
75
+ self.sidekiq_retries_exhausted_block = block
76
+ end
77
+
61
78
  DEFAULT_OPTIONS = { 'retry' => true, 'queue' => 'default' }
62
79
 
63
80
  def get_sidekiq_options # :nodoc:
@@ -4,7 +4,7 @@ require File.expand_path('../lib/sidekiq/version', __FILE__)
4
4
  Gem::Specification.new do |gem|
5
5
  gem.authors = ["Mike Perham"]
6
6
  gem.email = ["mperham@gmail.com"]
7
- gem.description = gem.summary = "Simple, efficient message processing for Ruby"
7
+ gem.description = gem.summary = "Simple, efficient background processing for Ruby"
8
8
  gem.homepage = "http://sidekiq.org"
9
9
  gem.license = "LGPL-3.0"
10
10
 
@@ -172,6 +172,18 @@ class TestApi < Minitest::Test
172
172
  assert_equal 0, q.size
173
173
  end
174
174
 
175
+ it "can move scheduled job to queue" do
176
+ job_id = ApiWorker.perform_in(100, 1, 'jason')
177
+ job = Sidekiq::ScheduledSet.new.find_job(job_id)
178
+ q = Sidekiq::Queue.new
179
+ job.add_to_queue
180
+ queued_job = q.find_job(job_id)
181
+ refute_nil queued_job
182
+ assert_equal queued_job.jid, job_id
183
+ job = Sidekiq::ScheduledSet.new.find_job(job_id)
184
+ assert_nil job
185
+ end
186
+
175
187
  it 'can find job by id in sorted sets' do
176
188
  job_id = ApiWorker.perform_in(100, 1, 'jason')
177
189
  job = Sidekiq::ScheduledSet.new.find_job(job_id)
@@ -12,12 +12,18 @@ class TestRetry < Minitest::Test
12
12
  def @redis.with; yield self; end
13
13
  end
14
14
 
15
+ let(:worker) do
16
+ Class.new do
17
+ include ::Sidekiq::Worker
18
+ end
19
+ end
20
+
15
21
  it 'allows disabling retry' do
16
22
  msg = { 'class' => 'Bob', 'args' => [1,2,'foo'], 'retry' => false }
17
23
  msg2 = msg.dup
18
24
  handler = Sidekiq::Middleware::Server::RetryJobs.new
19
25
  assert_raises RuntimeError do
20
- handler.call('', msg2, 'default') do
26
+ handler.call(worker, msg2, 'default') do
21
27
  raise "kerblammo!"
22
28
  end
23
29
  end
@@ -30,7 +36,7 @@ class TestRetry < Minitest::Test
30
36
  msg2 = msg.dup
31
37
  handler = Sidekiq::Middleware::Server::RetryJobs.new
32
38
  assert_raises RuntimeError do
33
- handler.call('', msg2, 'default') do
39
+ handler.call(worker, msg2, 'default') do
34
40
  raise "kerblammo!"
35
41
  end
36
42
  end
@@ -45,7 +51,7 @@ class TestRetry < Minitest::Test
45
51
  handler = Sidekiq::Middleware::Server::RetryJobs.new
46
52
  c = nil
47
53
  assert_raises RuntimeError do
48
- handler.call('', msg, 'default') do
54
+ handler.call(worker, msg, 'default') do
49
55
  c = caller(0); raise "kerblammo!"
50
56
  end
51
57
  end
@@ -60,7 +66,7 @@ class TestRetry < Minitest::Test
60
66
  handler = Sidekiq::Middleware::Server::RetryJobs.new
61
67
  c = nil
62
68
  assert_raises RuntimeError do
63
- handler.call('', msg, 'default') do
69
+ handler.call(worker, msg, 'default') do
64
70
  c = caller(0)[0..3]; raise "kerblammo!"
65
71
  end
66
72
  end
@@ -73,7 +79,7 @@ class TestRetry < Minitest::Test
73
79
  msg = { 'class' => 'Bob', 'args' => [1,2,'foo'], 'retry' => true }
74
80
  handler = Sidekiq::Middleware::Server::RetryJobs.new
75
81
  assert_raises RuntimeError do
76
- handler.call('', msg, 'default') do
82
+ handler.call(worker, msg, 'default') do
77
83
  raise "kerblammo!"
78
84
  end
79
85
  end
@@ -91,7 +97,7 @@ class TestRetry < Minitest::Test
91
97
  msg = { 'class' => 'Bob', 'args' => [1,2,'foo'], 'retry' => true, 'retry_queue' => 'retry' }
92
98
  handler = Sidekiq::Middleware::Server::RetryJobs.new
93
99
  assert_raises RuntimeError do
94
- handler.call('', msg, 'default') do
100
+ handler.call(worker, msg, 'default') do
95
101
  raise "kerblammo!"
96
102
  end
97
103
  end
@@ -110,7 +116,7 @@ class TestRetry < Minitest::Test
110
116
  msg = {"class"=>"Bob", "args"=>[1, 2, "foo"], 'retry' => true, "queue"=>"default", "error_message"=>"kerblammo!", "error_class"=>"RuntimeError", "failed_at"=>now, "retry_count"=>10}
111
117
  handler = Sidekiq::Middleware::Server::RetryJobs.new
112
118
  assert_raises RuntimeError do
113
- handler.call('', msg, 'default') do
119
+ handler.call(worker, msg, 'default') do
114
120
  raise "kerblammo!"
115
121
  end
116
122
  end
@@ -128,7 +134,7 @@ class TestRetry < Minitest::Test
128
134
  msg = {"class"=>"Bob", "args"=>[1, 2, "foo"], 'retry' => 10, "queue"=>"default", "error_message"=>"kerblammo!", "error_class"=>"RuntimeError", "failed_at"=>now, "retry_count"=>8}
129
135
  handler = Sidekiq::Middleware::Server::RetryJobs.new
130
136
  assert_raises RuntimeError do
131
- handler.call('', msg, 'default') do
137
+ handler.call(worker, msg, 'default') do
132
138
  raise "kerblammo!"
133
139
  end
134
140
  end
@@ -146,7 +152,7 @@ class TestRetry < Minitest::Test
146
152
  @redis.expect :zadd, 1, [ 'retry', String, String ]
147
153
  handler = Sidekiq::Middleware::Server::RetryJobs.new
148
154
  assert_raises RuntimeError do
149
- handler.call('', msg, 'default') do
155
+ handler.call(worker, msg, 'default') do
150
156
  raise "kerblammo!"
151
157
  end
152
158
  end
@@ -160,7 +166,7 @@ class TestRetry < Minitest::Test
160
166
  @redis.expect :zadd, 1, [ 'retry', String, String ]
161
167
  handler = Sidekiq::Middleware::Server::RetryJobs.new
162
168
  assert_raises RuntimeError do
163
- handler.call('', msg, 'default') do
169
+ handler.call(worker, msg, 'default') do
164
170
  raise "kerblammo!"
165
171
  end
166
172
  end
@@ -169,14 +175,45 @@ class TestRetry < Minitest::Test
169
175
  end
170
176
 
171
177
  describe "retry exhaustion" do
172
- let(:worker){ Minitest::Mock.new }
173
178
  let(:handler){ Sidekiq::Middleware::Server::RetryJobs.new }
179
+ let(:worker) { Minitest::Mock.new }
174
180
  let(:msg){ {"class"=>"Bob", "args"=>[1, 2, "foo"], "queue"=>"default", "error_message"=>"kerblammo!", "error_class"=>"RuntimeError", "failed_at"=>Time.now.utc, "retry"=>3, "retry_count"=>3} }
175
181
 
176
- it 'calls worker retries_exhausted after too many retries' do
177
- worker.expect(:retries_exhausted, true, [1,2,"foo"])
178
- task_misbehaving_worker
179
- worker.verify
182
+ describe "worker method" do
183
+ let(:worker) do
184
+ klass = Class.new do
185
+ include Sidekiq::Worker
186
+
187
+ def self.name; "Worker"; end
188
+
189
+ def retries_exhausted(*args)
190
+ args << "retried_method"
191
+ end
192
+ end
193
+ end
194
+
195
+ it 'calls worker.retries_exhausted after too many retries' do
196
+ assert_equal [1,2, "foo", "retried_method"], handler.retries_exhausted(worker.new, msg)
197
+ end
198
+ end
199
+
200
+ describe "worker block" do
201
+ let(:worker) do
202
+ Class.new do
203
+ include Sidekiq::Worker
204
+
205
+ sidekiq_retries_exhausted do |msg|
206
+ msg.tap {|m| m['called_by_callback'] = true }
207
+ end
208
+ end
209
+ end
210
+
211
+ it 'calls worker sidekiq_retries_exhausted_block after too many retries' do
212
+ new_msg = handler.retries_exhausted(worker.new, msg)
213
+ expected_msg = msg.merge('called_by_callback' => true)
214
+
215
+ assert_equal expected_msg, new_msg, "sidekiq_retries_exhausted block not called"
216
+ end
180
217
  end
181
218
 
182
219
  it 'handles and logs retries_exhausted failures gracefully (drops them)' do
@@ -197,6 +234,56 @@ class TestRetry < Minitest::Test
197
234
  end
198
235
  end
199
236
  end
237
+
238
+ describe "custom retry delay" do
239
+ before do
240
+ @old_logger = Sidekiq.logger
241
+ @tmp_log_path = '/tmp/sidekiq-retries.log'
242
+ Sidekiq.logger = Logger.new(@tmp_log_path)
243
+ end
244
+
245
+ after do
246
+ Sidekiq.logger = @old_logger
247
+ Sidekiq.options.delete(:logfile)
248
+ File.unlink @tmp_log_path if File.exists?(@tmp_log_path)
249
+ end
250
+
251
+ let(:custom_worker) do
252
+ Class.new do
253
+ include ::Sidekiq::Worker
254
+
255
+ sidekiq_retry_in do |count|
256
+ count * 2
257
+ end
258
+ end
259
+ end
260
+
261
+ let(:error_worker) do
262
+ Class.new do
263
+ include ::Sidekiq::Worker
264
+
265
+ sidekiq_retry_in do |count|
266
+ count / 0
267
+ end
268
+ end
269
+ end
270
+
271
+ let(:handler) { Sidekiq::Middleware::Server::RetryJobs.new }
272
+
273
+ it "retries with a default delay" do
274
+ refute_equal 4, handler.delay_for(worker, 2)
275
+ end
276
+
277
+ it "retries with a custom delay" do
278
+ assert_equal 4, handler.delay_for(custom_worker, 2)
279
+ end
280
+
281
+ it "falls back to the default retry on exception" do
282
+ refute_equal 4, handler.delay_for(error_worker, 2)
283
+ assert_match(/Failure scheduling retry using the defined `sidekiq_retry_in`/,
284
+ File.read(@tmp_log_path), 'Log entry missing for sidekiq_retry_in')
285
+ end
286
+ end
200
287
  end
201
288
 
202
289
  end
@@ -49,6 +49,7 @@ class TestTesting < Minitest::Test
49
49
  before do
50
50
  load 'sidekiq/testing.rb'
51
51
  EnqueuedWorker.jobs.clear
52
+ DirectWorker.jobs.clear
52
53
  end
53
54
 
54
55
  after do
@@ -112,6 +113,36 @@ class TestTesting < Minitest::Test
112
113
 
113
114
  end
114
115
 
116
+ class SpecificJidWorker
117
+ include Sidekiq::Worker
118
+ class_attribute :count
119
+ self.count = 0
120
+ def perform(worker_jid)
121
+ return unless worker_jid == self.jid
122
+ self.class.count += 1
123
+ end
124
+ end
125
+
126
+ it 'execute only jobs with assigned JID' do
127
+ 4.times do |i|
128
+ jid = SpecificJidWorker.perform_async(nil)
129
+ if i % 2 == 0
130
+ SpecificJidWorker.jobs[-1]["args"] = ["wrong_jid"]
131
+ else
132
+ SpecificJidWorker.jobs[-1]["args"] = [jid]
133
+ end
134
+ end
135
+
136
+ SpecificJidWorker.perform_one
137
+ assert_equal 0, SpecificJidWorker.count
138
+
139
+ SpecificJidWorker.perform_one
140
+ assert_equal 1, SpecificJidWorker.count
141
+
142
+ SpecificJidWorker.drain
143
+ assert_equal 2, SpecificJidWorker.count
144
+ end
145
+
115
146
  it 'round trip serializes the job arguments' do
116
147
  assert StoredWorker.perform_async(:mike)
117
148
  job = StoredWorker.jobs.first
@@ -0,0 +1,18 @@
1
+ require 'helper'
2
+ require 'sidekiq/util'
3
+
4
+ class TestUtil < Minitest::Test
5
+ describe 'util' do
6
+ it 'generates the same process id when included in two or more classes' do
7
+ class One
8
+ include Sidekiq::Util
9
+ end
10
+
11
+ class Two
12
+ include Sidekiq::Util
13
+ end
14
+
15
+ assert_equal One.new.process_id, Two.new.process_id
16
+ end
17
+ end
18
+ end
@@ -76,6 +76,26 @@ class TestWeb < Minitest::Test
76
76
  end
77
77
  end
78
78
 
79
+ it 'can clear an empty worker list' do
80
+ post '/reset'
81
+ assert_equal 302, last_response.status
82
+ end
83
+
84
+ it 'can clear a non-empty worker list' do
85
+ Sidekiq.redis do |conn|
86
+ identity = 'foo'
87
+ conn.sadd('workers', identity)
88
+ end
89
+
90
+ post '/reset'
91
+
92
+ assert_equal 302, last_response.status
93
+
94
+ Sidekiq.redis do |conn|
95
+ refute conn.smembers('workers').any?
96
+ end
97
+ end
98
+
79
99
  it 'can delete a job' do
80
100
  Sidekiq.redis do |conn|
81
101
  conn.rpush('queue:foo', "{}")
@@ -178,6 +198,21 @@ class TestWeb < Minitest::Test
178
198
  end
179
199
  end
180
200
 
201
+ it "can move scheduled to default queue" do
202
+ params = add_scheduled
203
+ Sidekiq.redis do |conn|
204
+ assert_equal 1, conn.zcard('schedule')
205
+ assert_equal 0, conn.zcard('default')
206
+ post '/scheduled', 'key' => [job_params(*params)], 'add_to_queue' => 'AddToQueue'
207
+ assert_equal 302, last_response.status
208
+ assert_equal 'http://example.org/scheduled', last_response.header['Location']
209
+ assert_equal 0, conn.zcard('schedule')
210
+ get '/queues/default'
211
+ assert_equal 200, last_response.status
212
+ assert_match /#{params[0]['args'][2]}/, last_response.body
213
+ end
214
+ end
215
+
181
216
  it 'can retry all retries' do
182
217
  msg, score = add_retry
183
218
  add_retry
@@ -24,6 +24,7 @@ da:
24
24
  ShowAll: Vis alle
25
25
  CurrentMessagesInQueue: Nuværende beskeder i <span class='title'>%{queue}</span>
26
26
  Delete: Slet
27
+ AddToQueue: Tilføj til kø
27
28
  AreYouSureDeleteJob: Er du sikker på at du vil slette dette job?
28
29
  AreYouSureDeleteQueue: Er du sikker på at du vil slette %{queue} køen?
29
30
  Queues: Køer
@@ -24,6 +24,7 @@ de:
24
24
  ShowAll: Alle anzeigen
25
25
  CurrentMessagesInQueue: Aktuelle Nachrichten in <span class='title'>%{queue}</span>
26
26
  Delete: Löschen
27
+ AddToQueue: Add to queue
27
28
  AreYouSureDeleteJob: Möchtest du diesen Job wirklich löschen?
28
29
  AreYouSureDeleteQueue: Möchtest du %{queue} wirklich löschen?
29
30
  Queues: Warteschlangen
@@ -26,6 +26,7 @@ en: # <---- change this to your locale code
26
26
  ShowAll: Show All
27
27
  CurrentMessagesInQueue: Current messages in <span class='title'>%{queue}</span>
28
28
  Delete: Delete
29
+ AddToQueue: Add to queue
29
30
  AreYouSureDeleteJob: Are you sure you want to delete this job?
30
31
  AreYouSureDeleteQueue: Are you sure you want to delete the %{queue} queue?
31
32
  Queues: Queues
@@ -24,6 +24,7 @@ es:
24
24
  ShowAll: Mostrar Todo
25
25
  CurrentMessagesInQueue: Mensajes actualmente en <span class='title'>%{queue}</span>
26
26
  Delete: Eliminar
27
+ AddToQueue: Añadir a fila
27
28
  AreYouSureDeleteJob: ¿Estás seguro de eliminar este trabajo?
28
29
  AreYouSureDeleteQueue: ¿Estás seguro de eliminar la fila %{queue}?
29
30
  Queues: Filas
@@ -24,6 +24,7 @@ fr:
24
24
  ShowAll: Montrer Tout
25
25
  CurrentMessagesInQueue: Messages actuellement dans <span class='title'>%{queue}</span>
26
26
  Delete: Supprimer
27
+ AddToQueue: Ajouter à la liste
27
28
  AreYouSureDeleteJob: Êtes-vous certain de vouloir supprimer cette tâche?
28
29
  AreYouSureDeleteQueue: Êtes-vous certain de vouloir supprimer la file %{queue}?
29
30
  Queues: Queues
@@ -24,6 +24,7 @@ it:
24
24
  ShowAll: Mostra tutti
25
25
  CurrentMessagesInQueue: Messaggi in <span class='title'>%{queue}</span>
26
26
  Delete: Cancella
27
+ AddToQueue: Aggiungi a coda
27
28
  AreYouSureDeleteJob: Sei sicuro di voler cancellare questo lavoro?
28
29
  AreYouSureDeleteQueue: Sei sicuro di voler cancellare la coda %{queue}?
29
30
  Queues: Code
@@ -25,6 +25,7 @@ ja:
25
25
  ShowAll: 全て見せる
26
26
  CurrentMessagesInQueue: <span class='title'>%{queue}</span>に メッセージがあります
27
27
  Delete: 削除
28
+ AddToQueue: キューに追加
28
29
  AreYouSureDeleteJob: このジョブを削除しますか?
29
30
  AreYouSureDeleteQueue: この %{queue} キューを削除しますか?
30
31
  Queues: キュー
@@ -25,6 +25,7 @@ ko:
25
25
  ShowAll: 모두 보기
26
26
  CurrentMessagesInQueue: <span class='title'>%{queue}</span>에 대기 중인 메시지
27
27
  Delete: 삭제
28
+ AddToQueue: 큐 추가
28
29
  AreYouSureDeleteJob: 이 작업을 삭제하시겠습니까?
29
30
  AreYouSureDeleteQueue: 이 %{queue} 큐를 삭제하시겠습니까?
30
31
  Queues: 큐
@@ -25,6 +25,7 @@ nl:
25
25
  ShowAll: Toon alle
26
26
  CurrentMessagesInQueue: Aantal berichten in <span class='title'>%{queue}</span>
27
27
  Delete: Verwijderen
28
+ AddToQueue: Toevoegen aan wachtrij
28
29
  AreYouSureDeleteJob: Weet u zeker dat u deze taak wilt verwijderen?
29
30
  AreYouSureDeleteQueue: Weet u zeker dat u wachtrij %{queue} wilt verwijderen?
30
31
  Queues: Wachtrijen
@@ -25,6 +25,7 @@ no:
25
25
  ShowAll: Vis alle
26
26
  CurrentMessagesInQueue: Nåværende melding i <span class='title'>%{queue}</span>
27
27
  Delete: Slett
28
+ AddToQueue: Legg til i kø
28
29
  AreYouSureDeleteJob: Er du sikker på at du vil slette denne jobben?
29
30
  AreYouSureDeleteQueue: Er du sikker på at du vil slette køen %{queue}?
30
31
  Queues: Køer
@@ -24,6 +24,7 @@ pl:
24
24
  ShowAll: Pokaż wszystko
25
25
  CurrentMessagesInQueue: Aktualne wiadomości w kolejce <span class='title'>%{queue}</span>
26
26
  Delete: Usuń
27
+ AddToQueue: dodaj do kolejki
27
28
  AreYouSureDeleteJob: Czy na pewno usunąć to zadanie?
28
29
  AreYouSureDeleteQueue: Czy na pewno usunąć kolejkę %{queue}?
29
30
  Queues: Kolejki
@@ -25,6 +25,7 @@
25
25
  ShowAll: Mostrar todos
26
26
  CurrentMessagesInQueue: Mensagens atualmenta na <span class='title'>%{queue}</span>
27
27
  Delete: Apagar
28
+ AddToQueue: Adicionar à fila
28
29
  AreYouSureDeleteJob: Deseja deletar esta tarefa?
29
30
  AreYouSureDeleteQueue: Deseja deletar a %{queue} fila?
30
31
  Queues: Filas
@@ -24,6 +24,7 @@ pt:
24
24
  ShowAll: Mostrar todos
25
25
  CurrentMessagesInQueue: Mensagens na fila <span class='title'>%{queue}</span>
26
26
  Delete: Apagar
27
+ AddToQueue: Adicionar à fila
27
28
  AreYouSureDeleteJob: Tem a certeza que deseja eliminar esta tarefa?
28
29
  AreYouSureDeleteQueue: Tem a certeza que deseja eliminar a fila %{queue}?
29
30
  Queues: Filas
@@ -24,6 +24,7 @@ ru:
24
24
  ShowAll: Показать все
25
25
  CurrentMessagesInQueue: Текущие сообщения в <span class='title'>%{queue}</span>
26
26
  Delete: Удалить
27
+ AddToQueue: Добавить в очередь
27
28
  AreYouSureDeleteJob: Вы уверены в том, что хотите удалить задание?
28
29
  AreYouSureDeleteQueue: Вы уверены в том, что хотите удалить очередь %{queue}?
29
30
  Queues: Очереди
@@ -26,5 +26,6 @@ header.row
26
26
  td= msg['class']
27
27
  td= display_args(msg['args'])
28
28
  input.btn.btn-danger.pull-right type="submit" name="delete" value="#{t('Delete')}"
29
+ input.btn.btn-danger.pull-right type="submit" name="add_to_queue" value="#{t('AddToQueue')}"
29
30
  - else
30
31
  .alert.alert-success = t('NoScheduledFound')
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sidekiq
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.12.4
4
+ version: 2.13.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-06-13 00:00:00.000000000 Z
12
+ date: 2013-07-09 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: redis
@@ -203,7 +203,7 @@ dependencies:
203
203
  - - ! '>='
204
204
  - !ruby/object:Gem::Version
205
205
  version: '0'
206
- description: Simple, efficient message processing for Ruby
206
+ description: Simple, efficient background processing for Ruby
207
207
  email:
208
208
  - mperham@gmail.com
209
209
  executables:
@@ -278,6 +278,7 @@ files:
278
278
  - test/test_sidekiq.rb
279
279
  - test/test_testing.rb
280
280
  - test/test_testing_inline.rb
281
+ - test/test_util.rb
281
282
  - test/test_web.rb
282
283
  - web/assets/images/bootstrap/glyphicons-halflings-white.png
283
284
  - web/assets/images/bootstrap/glyphicons-halflings.png
@@ -340,7 +341,7 @@ rubyforge_project:
340
341
  rubygems_version: 1.8.23
341
342
  signing_key:
342
343
  specification_version: 3
343
- summary: Simple, efficient message processing for Ruby
344
+ summary: Simple, efficient background processing for Ruby
344
345
  test_files:
345
346
  - test/config.yml
346
347
  - test/env_based_config.yml
@@ -362,4 +363,5 @@ test_files:
362
363
  - test/test_sidekiq.rb
363
364
  - test/test_testing.rb
364
365
  - test/test_testing_inline.rb
366
+ - test/test_util.rb
365
367
  - test/test_web.rb