sidekiq 2.5.3 → 2.5.4

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,4 +1,14 @@
1
- HEAD
1
+ 2.5.4
2
+ -----------
3
+
4
+ - `Sidekiq::Client.push` now accepts the worker class as a string so the
5
+ Sidekiq client does not have to load your worker classes at all. [#524]
6
+ - `Sidekiq::Client.push_bulk` now works with inline testing.
7
+ - **Really** fix status icon in Web UI this time.
8
+ - Add "Delete All" and "Retry All" buttons to Retries in Web UI
9
+
10
+
11
+ 2.5.3
2
12
  -----------
3
13
 
4
14
  - Small Web UI fixes
data/lib/sidekiq/api.rb CHANGED
@@ -43,6 +43,15 @@ module Sidekiq
43
43
  end
44
44
  end
45
45
  end
46
+
47
+ def clear
48
+ Sidekiq.redis do |conn|
49
+ conn.multi do
50
+ conn.del("queue:#{name}")
51
+ conn.srem("queues", name)
52
+ end
53
+ end
54
+ end
46
55
  end
47
56
 
48
57
  ##
@@ -143,6 +152,12 @@ module Sidekiq
143
152
  end
144
153
  count != 0
145
154
  end
155
+
156
+ def clear
157
+ Sidekiq.redis do |conn|
158
+ conn.del(@zset)
159
+ end
160
+ end
146
161
  end
147
162
 
148
163
  ##
data/lib/sidekiq/cli.rb CHANGED
@@ -126,12 +126,23 @@ module Sidekiq
126
126
  require 'sidekiq/rails'
127
127
  require File.expand_path("#{options[:require]}/config/environment.rb")
128
128
  ::Rails.application.eager_load!
129
- options[:tag] ||= File.basename(::Rails.root)
129
+ options[:tag] ||= default_tag
130
130
  else
131
131
  require options[:require]
132
132
  end
133
133
  end
134
134
 
135
+ def default_tag
136
+ dir = ::Rails.root
137
+ name = File.basename(dir)
138
+ if name.to_i != 0 && prevdir = File.dirname(dir) # Capistrano release directory?
139
+ if File.basename(prevdir) == 'releases'
140
+ return File.basename(File.dirname(prevdir))
141
+ end
142
+ end
143
+ name
144
+ end
145
+
135
146
  def validate!
136
147
  options[:queues] << 'default' if options[:queues].empty?
137
148
 
@@ -65,13 +65,7 @@ module Sidekiq
65
65
  end.compact
66
66
 
67
67
  pushed = false
68
- Sidekiq.redis do |conn|
69
- _, pushed = conn.multi do
70
- conn.sadd('queues', normed['queue'])
71
- conn.rpush("queue:#{normed['queue']}", payloads)
72
- end
73
- end
74
-
68
+ pushed = raw_push(normed, payloads)
75
69
  pushed ? payloads.size : nil
76
70
  end
77
71
 
@@ -98,7 +92,9 @@ module Sidekiq
98
92
  def self.raw_push(normed, payload) # :nodoc:
99
93
  pushed = false
100
94
  Sidekiq.redis do |conn|
101
- if normed['at']
95
+ if normed['at'] && payload.is_a?(Array)
96
+ pushed = conn.zadd('schedule', payload.map {|hash| [normed['at'].to_s, hash]})
97
+ elsif normed['at']
102
98
  pushed = conn.zadd('schedule', normed['at'].to_s, payload)
103
99
  else
104
100
  _, pushed = conn.multi do
@@ -122,13 +118,17 @@ module Sidekiq
122
118
  def self.normalize_item(item)
123
119
  raise(ArgumentError, "Message must be a Hash of the form: { 'class' => SomeWorker, 'args' => ['bob', 1, :foo => 'bar'] }") unless item.is_a?(Hash)
124
120
  raise(ArgumentError, "Message must include a class and set of arguments: #{item.inspect}") if !item['class'] || !item['args']
125
- raise(ArgumentError, "Message must include a Sidekiq::Worker class, not class name: #{item['class'].ancestors.inspect}") if !item['class'].is_a?(Class) || !item['class'].respond_to?('get_sidekiq_options')
121
+ raise(ArgumentError, "Message class must be either a Class or String representation of the class name") unless item['class'].is_a?(Class) || item['class'].is_a?(String)
122
+
123
+ if item['class'].is_a?(Class)
124
+ raise(ArgumentError, "Message must include a Sidekiq::Worker class, not class name: #{item['class'].ancestors.inspect}") if !item['class'].respond_to?('get_sidekiq_options')
125
+ normalized_item = item['class'].get_sidekiq_options.merge(item)
126
+ normalized_item['class'] = normalized_item['class'].to_s
127
+ else
128
+ normalized_item = Sidekiq::Worker::ClassMethods::DEFAULT_OPTIONS.merge(item)
129
+ end
126
130
 
127
- normalized_item = item['class'].get_sidekiq_options.merge(item.dup)
128
- normalized_item['class'] = normalized_item['class'].to_s
129
- normalized_item['retry'] = !!normalized_item['retry'] unless normalized_item['retry'].is_a?(Fixnum)
130
131
  normalized_item['jid'] = SecureRandom.hex(12)
131
-
132
132
  normalized_item
133
133
  end
134
134
 
@@ -28,8 +28,11 @@ module Sidekiq
28
28
  #
29
29
  singleton_class.class_eval do
30
30
  alias_method :raw_push_old, :raw_push
31
- def raw_push(hash, _)
32
- hash['class'].constantize.new.perform(*Sidekiq.load_json(Sidekiq.dump_json(hash['args'])))
31
+ def raw_push(normed, payload)
32
+ Array.wrap(payload).each do |hash|
33
+ normed['class'].constantize.new.perform(*Sidekiq.load_json(hash)['args'])
34
+ end
35
+
33
36
  true
34
37
  end
35
38
  end
@@ -1,3 +1,3 @@
1
1
  module Sidekiq
2
- VERSION = "2.5.3"
2
+ VERSION = "2.5.4"
3
3
  end
data/lib/sidekiq/web.rb CHANGED
@@ -136,10 +136,7 @@ module Sidekiq
136
136
  end
137
137
 
138
138
  post "/queues/:name" do
139
- Sidekiq.redis do |conn|
140
- conn.del("queue:#{params[:name]}")
141
- conn.srem("queues", params[:name])
142
- end
139
+ Sidekiq::Queue.new(params[:name]).clear
143
140
  redirect "#{root_path}queues"
144
141
  end
145
142
 
@@ -195,6 +192,18 @@ module Sidekiq
195
192
  redirect "#{root_path}retries"
196
193
  end
197
194
 
195
+ post "/retries/all/delete" do
196
+ Sidekiq::RetrySet.new.clear
197
+ redirect "#{root_path}retries"
198
+ end
199
+
200
+ post "/retries/all/retry" do
201
+ Sidekiq::RetrySet.new.each do |job|
202
+ process_score('retry', job.score, :retry)
203
+ end
204
+ redirect "#{root_path}retries"
205
+ end
206
+
198
207
  post "/retries/:score" do
199
208
  halt 404 unless params[:score]
200
209
  score = params[:score].to_f
data/test/test_api.rb CHANGED
@@ -36,6 +36,17 @@ class TestApi < MiniTest::Unit::TestCase
36
36
  assert_equal 0, q.size
37
37
  end
38
38
 
39
+ it 'can clear a queue' do
40
+ q = Sidekiq::Queue.new
41
+ 2.times { ApiWorker.perform_async(1, 'mike') }
42
+ q.clear
43
+
44
+ Sidekiq.redis do |conn|
45
+ refute conn.smembers('queues').include?('foo')
46
+ refute conn.exists('queues:foo')
47
+ end
48
+ end
49
+
39
50
  it 'shows empty retries' do
40
51
  r = Sidekiq::RetrySet.new
41
52
  assert_equal 0, r.size
@@ -64,9 +75,18 @@ class TestApi < MiniTest::Unit::TestCase
64
75
  assert_equal 0, r.size
65
76
  end
66
77
 
67
- def add_retry
78
+ it 'can clear retries' do
79
+ add_retry
80
+ add_retry('test')
81
+ r = Sidekiq::RetrySet.new
82
+ assert_equal 2, r.size
83
+ r.clear
84
+ assert_equal 0, r.size
85
+ end
86
+
87
+ def add_retry(jid = 'bob')
68
88
  at = Time.now.to_f
69
- payload = Sidekiq.dump_json('class' => 'ApiWorker', 'args' => [1, 'mike'], 'queue' => 'default', 'jid' => 'bob')
89
+ payload = Sidekiq.dump_json('class' => 'ApiWorker', 'args' => [1, 'mike'], 'queue' => 'default', 'jid' => jid)
70
90
  Sidekiq.redis do |conn|
71
91
  conn.zadd('retry', at.to_s, payload)
72
92
  end
data/test/test_client.rb CHANGED
@@ -30,6 +30,15 @@ class TestClient < MiniTest::Unit::TestCase
30
30
  assert_raises ArgumentError do
31
31
  Sidekiq::Client.push('foo', :class => 'Foo', :noargs => [1, 2])
32
32
  end
33
+
34
+ assert_raises ArgumentError do
35
+ Sidekiq::Client.push('queue' => 'foo', 'class' => MyWorker, 'noargs' => [1, 2])
36
+ end
37
+
38
+ assert_raises ArgumentError do
39
+ Sidekiq::Client.push('queue' => 'foo', 'class' => 42, 'args' => [1, 2])
40
+ end
41
+
33
42
  end
34
43
 
35
44
  it 'pushes messages to redis' do
@@ -40,6 +49,14 @@ class TestClient < MiniTest::Unit::TestCase
40
49
  @redis.verify
41
50
  end
42
51
 
52
+ it 'pushes messages to redis using a String class' do
53
+ @redis.expect :rpush, 1, ['queue:foo', String]
54
+ pushed = Sidekiq::Client.push('queue' => 'foo', 'class' => 'MyWorker', 'args' => [1, 2])
55
+ assert pushed
56
+ assert_equal 24, pushed.size
57
+ @redis.verify
58
+ end
59
+
43
60
  class MyWorker
44
61
  include Sidekiq::Worker
45
62
  end
@@ -105,6 +122,11 @@ class TestClient < MiniTest::Unit::TestCase
105
122
  count = Sidekiq::Client.push_bulk('class' => QueuedWorker, 'args' => (1..1_000).to_a.map { |x| Array(x) })
106
123
  assert_equal 1_000, count
107
124
  end
125
+ it 'can push a large set of jobs at once using a String class' do
126
+ a = Time.now
127
+ count = Sidekiq::Client.push_bulk('class' => 'QueuedWorker', 'args' => (1..1_000).to_a.map { |x| Array(x) })
128
+ assert_equal 1_000, count
129
+ end
108
130
  end
109
131
 
110
132
  class BaseWorker
@@ -28,6 +28,12 @@ class TestScheduling < MiniTest::Unit::TestCase
28
28
  assert ScheduledWorker.perform_in(5.days.from_now, 'mike')
29
29
  @redis.verify
30
30
  end
31
+
32
+ it 'schedules multiple jobs at once' do
33
+ @redis.expect :zadd, true, ['schedule', Array]
34
+ assert Sidekiq::Client.push_bulk('class' => ScheduledWorker, 'args' => ['mike', 'mike'], 'at' => 600)
35
+ @redis.verify
36
+ end
31
37
  end
32
38
 
33
39
  end
@@ -80,6 +80,14 @@ class TestInline < MiniTest::Unit::TestCase
80
80
  end
81
81
  end
82
82
 
83
+ it 'stubs the push_bulk call when in testing mode' do
84
+ assert Sidekiq::Client.push_bulk({'class' => InlineWorker, 'args' => [true, true]})
85
+
86
+ assert_raises InlineError do
87
+ Sidekiq::Client.push_bulk({'class' => InlineWorker, 'args' => [true, false]})
88
+ end
89
+ end
90
+
83
91
  it 'should relay parameters through json' do
84
92
  assert Sidekiq::Client.enqueue(InlineWorkerWithTimeParam, Time.now)
85
93
  end
data/test/test_web.rb CHANGED
@@ -72,9 +72,10 @@ class TestWeb < MiniTest::Unit::TestCase
72
72
 
73
73
  Sidekiq.redis do |conn|
74
74
  refute conn.smembers('queues').include?('foo')
75
+ refute conn.exists('queues:foo')
75
76
  end
76
77
  end
77
-
78
+
78
79
  it 'can delete a job' do
79
80
  Sidekiq.redis do |conn|
80
81
  conn.rpush('queue:foo', "{}")
@@ -154,6 +155,15 @@ class TestWeb < MiniTest::Unit::TestCase
154
155
  refute_match /#{score}/, last_response.body
155
156
  end
156
157
 
158
+ it 'can delete all retries' do
159
+ 3.times { add_retry }
160
+
161
+ post "/retries/all/delete", 'delete' => 'Delete'
162
+ assert_equal 0, Sidekiq::RetrySet.new.size
163
+ assert_equal 302, last_response.status
164
+ assert_equal 'http://example.org/retries', last_response.header['Location']
165
+ end
166
+
157
167
  it 'can retry a single retry now' do
158
168
  msg, score = add_retry
159
169
 
@@ -166,6 +176,20 @@ class TestWeb < MiniTest::Unit::TestCase
166
176
  assert_match /#{msg['args'][2]}/, last_response.body
167
177
  end
168
178
 
179
+ it 'can retry all retries' do
180
+ msg, score = add_retry
181
+ add_retry
182
+
183
+ post "/retries/all/retry", 'retry' => 'Retry'
184
+ assert_equal 302, last_response.status
185
+ assert_equal 'http://example.org/retries', last_response.header['Location']
186
+ assert_equal 2, Sidekiq::Queue.new("default").size
187
+
188
+ get '/queues/default'
189
+ assert_equal 200, last_response.status
190
+ assert_match /#{msg['args'][2]}/, last_response.body
191
+ end
192
+
169
193
  it 'can show user defined tab' do
170
194
  begin
171
195
  Sidekiq::Web.tabs['Custom Tab'] = '/custom'
@@ -216,12 +216,12 @@ header.row .pagination {
216
216
  padding: 4px 0 2px 0;
217
217
  }
218
218
  .summary_bar ul .desc {
219
- font-size: 1.1em;
219
+ font-size: 1em;
220
220
  font-weight: normal;
221
221
  }
222
222
  .summary_bar ul .count {
223
223
  color: #b1003e;
224
- font-size: 1.1em;
224
+ font-size: 1em;
225
225
  font-weight: bold;
226
226
  float: right;
227
227
  }
@@ -447,7 +447,7 @@ img.smallogo {
447
447
  }
448
448
 
449
449
  .status-sprite {
450
- background-image: url(/images/status-sd8051fd480.png);
450
+ background-image: url(../images/status-sd8051fd480.png);
451
451
  height: 30px;
452
452
  width: 30px;
453
453
  display: inline-block;
data/web/views/_nav.slim CHANGED
@@ -9,5 +9,9 @@
9
9
  div.nav-collapse
10
10
  ul.nav
11
11
  - tabs.each do |title, url|
12
- li class="#{(current_path==url) ? 'active':''}"
13
- a href='#{{root_path}}#{{url}}' #{title}
12
+ - if url.blank?
13
+ li class="#{(current_path == url) ? 'active':''}"
14
+ a href='#{{root_path}}#{{url}}' #{title}
15
+ - else
16
+ li class="#{(current_path =~ Regexp.new(url)) ? 'active':''}"
17
+ a href='#{{root_path}}#{{url}}' #{title}
@@ -28,7 +28,13 @@ header.row
28
28
  a href="#{root_path}queues/#{msg['queue']}" #{msg['queue']}
29
29
  td= msg['class']
30
30
  td= display_args(msg['args'])
31
- input.btn.btn-danger.btn-small.pull-right type="submit" name="delete" value="Delete"
32
- input.btn.btn-primary.btn-small.pull-right type="submit" name="retry" value="Retry Now"
31
+ input.btn.btn-primary.btn-small.pull-left type="submit" name="retry" value="Retry Now"
32
+ input.btn.btn-danger.btn-small.pull-left type="submit" name="delete" value="Delete"
33
+
34
+ form action="#{root_path}retries/all/delete" method="post"
35
+ input.btn.btn-danger.btn-small.pull-right type="submit" name="delete" value="Delete All" data-confirm="Are you sure?"
36
+ form action="#{root_path}retries/all/retry" method="post"
37
+ input.btn.btn-danger.btn-small.pull-right type="submit" name="retry" value="Retry All" data-confirm="Are you sure?"
38
+
33
39
  - else
34
40
  .alert.alert-success No retries were found
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.5.3
4
+ version: 2.5.4
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: 2012-11-15 00:00:00.000000000 Z
12
+ date: 2012-11-27 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: redis