sidekiq 2.17.6 → 2.17.7

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: 0d42c2e9a872cd5b00e30147f9d72aa587dc2a33
4
- data.tar.gz: 0d8a3223a321ae8aff8da8c468ca43a14bd0a851
3
+ metadata.gz: 37ea727f6e186178793472075b5b8c98aa1ff6fa
4
+ data.tar.gz: d95a324293b763a29f291f69d257e79f37468ba8
5
5
  SHA512:
6
- metadata.gz: 042f1408d57e3327c9391543e2bbf0e4d6f02ba7d7f3db9f7beccb4d91ef54d165d14b210b0b0d2b3b6be69e6212e1f72fc51648d3a71fb17959dbfd78d08d29
7
- data.tar.gz: e663acb2a1fbf05ef5ca4ccae9adc2d9704610f3e281be4072a1621538b2b0507f9bc37958bb397eb3af45af6df12d4b4db76dd7da605513adb10857f1f2863a
6
+ metadata.gz: ac8aaddac1fbc4312444129640e4137b5a93772f7246241af77e05a10d05a509ec342cbce8ae1351689fac0b5fdaffbbde36331b936c5fd2f62684c6bb2b1cde
7
+ data.tar.gz: 7c4ee6d1f8d8cf1c6aba0f74ef2db62a9f59e17847094d648af5b8fc75e5e31aeba0d6e1c1d529118f79f55adf66ce56e2915da4e7758d64ef8afcfc8b1d425e
data/Changes.md CHANGED
@@ -1,3 +1,11 @@
1
+ 2.17.7
2
+ -----------
3
+
4
+ - Auto-prune jobs older than one hour from the Workers page [#1508]
5
+ - Add Sidekiq::Workers#prune which can perform the auto-pruning.
6
+ - Fix issue where a job could be lost when an exception occurs updating
7
+ Redis stats before the job executes [#1511]
8
+
1
9
  2.17.6
2
10
  -----------
3
11
 
@@ -424,9 +424,10 @@ module Sidekiq
424
424
  Sidekiq.redis do |conn|
425
425
  workers = conn.smembers("workers")
426
426
  workers.each do |w|
427
- msg, time = conn.mget("worker:#{w}", "worker:#{w}:started")
428
- next unless msg
429
- block.call(w, Sidekiq.load_json(msg), time)
427
+ json = conn.get("worker:#{w}")
428
+ next unless json
429
+ msg = Sidekiq.load_json(json)
430
+ block.call(w, msg, Time.at(msg['run_at']).to_s)
430
431
  end
431
432
  end
432
433
  end
@@ -436,6 +437,36 @@ module Sidekiq
436
437
  conn.scard("workers")
437
438
  end.to_i
438
439
  end
440
+
441
+ # Prune old worker entries from the Busy set. Worker entries
442
+ # can be orphaned if Sidekiq hard crashes while processing jobs.
443
+ # Default is to delete worker entries older than one hour.
444
+ #
445
+ # Returns the number of records removed.
446
+ def prune(older_than=60*60)
447
+ to_rem = []
448
+ Sidekiq.redis do |conn|
449
+ conn.smembers('workers').each do |w|
450
+ msg = conn.get("worker:#{w}")
451
+ if !msg
452
+ to_rem << w
453
+ else
454
+ m = Sidekiq.load_json(msg)
455
+ run_at = Time.at(m['run_at'])
456
+ # prune jobs older than one hour
457
+ if run_at < (Time.now - older_than)
458
+ to_rem << w
459
+ else
460
+ end
461
+ end
462
+ end
463
+ end
464
+
465
+ if to_rem.size > 0
466
+ Sidekiq.redis { |conn| conn.srem('workers', to_rem) }
467
+ end
468
+ to_rem.size
469
+ end
439
470
  end
440
471
 
441
472
  end
@@ -92,38 +92,45 @@ module Sidekiq
92
92
  end
93
93
 
94
94
  def stats(worker, msg, queue)
95
- redis do |conn|
96
- conn.multi do
97
- conn.sadd('workers', identity)
98
- conn.setex("worker:#{identity}:started", EXPIRY, Time.now.to_s)
99
- hash = {:queue => queue, :payload => msg, :run_at => Time.now.to_i }
100
- conn.setex("worker:#{identity}", EXPIRY, Sidekiq.dump_json(hash))
95
+ # Do not conflate errors from the job with errors caused by updating stats so calling code can react appropriately
96
+ retry_and_suppress_exceptions do
97
+ redis do |conn|
98
+ conn.multi do
99
+ conn.sadd('workers', identity)
100
+ conn.setex("worker:#{identity}:started", EXPIRY, Time.now.to_s)
101
+ hash = {:queue => queue, :payload => msg, :run_at => Time.now.to_i }
102
+ conn.setex("worker:#{identity}", EXPIRY, Sidekiq.dump_json(hash))
103
+ end
101
104
  end
102
105
  end
103
106
 
104
107
  begin
105
108
  yield
106
109
  rescue Exception
107
- redis do |conn|
108
- failed = "stat:failed:#{Time.now.utc.to_date}"
109
- result = conn.multi do
110
- conn.incrby("stat:failed", 1)
111
- conn.incrby(failed, 1)
110
+ retry_and_suppress_exceptions do
111
+ redis do |conn|
112
+ failed = "stat:failed:#{Time.now.utc.to_date}"
113
+ result = conn.multi do
114
+ conn.incrby("stat:failed", 1)
115
+ conn.incrby(failed, 1)
116
+ end
117
+ conn.expire(failed, STATS_TIMEOUT) if result.last == 1
112
118
  end
113
- conn.expire(failed, STATS_TIMEOUT) if result.last == 1
114
119
  end
115
120
  raise
116
121
  ensure
117
- redis do |conn|
118
- processed = "stat:processed:#{Time.now.utc.to_date}"
119
- result = conn.multi do
120
- conn.srem("workers", identity)
121
- conn.del("worker:#{identity}")
122
- conn.del("worker:#{identity}:started")
123
- conn.incrby("stat:processed", 1)
124
- conn.incrby(processed, 1)
122
+ retry_and_suppress_exceptions do
123
+ redis do |conn|
124
+ processed = "stat:processed:#{Time.now.utc.to_date}"
125
+ result = conn.multi do
126
+ conn.srem("workers", identity)
127
+ conn.del("worker:#{identity}")
128
+ conn.del("worker:#{identity}:started")
129
+ conn.incrby("stat:processed", 1)
130
+ conn.incrby(processed, 1)
131
+ end
132
+ conn.expire(processed, STATS_TIMEOUT) if result.last == 1
125
133
  end
126
- conn.expire(processed, STATS_TIMEOUT) if result.last == 1
127
134
  end
128
135
  end
129
136
  end
@@ -137,5 +144,23 @@ module Sidekiq
137
144
  def cloned(ary)
138
145
  Marshal.load(Marshal.dump(ary))
139
146
  end
147
+
148
+ # If an exception occurs in the block passed to this method, that block will be retried up to max_retries times.
149
+ # All exceptions will be swallowed and logged.
150
+ def retry_and_suppress_exceptions(max_retries = 2)
151
+ retry_count = 0
152
+ begin
153
+ yield
154
+ rescue => e
155
+ retry_count += 1
156
+ if retry_count <= max_retries
157
+ Sidekiq.logger.debug {"Suppressing and retrying error: #{e.inspect}"}
158
+ sleep(1)
159
+ retry
160
+ else
161
+ Sidekiq.logger.info {"Exhausted #{max_retries} retries due to Redis timeouts: #{e.inspect}"}
162
+ end
163
+ end
164
+ end
140
165
  end
141
166
  end
@@ -1,3 +1,3 @@
1
1
  module Sidekiq
2
- VERSION = "2.17.6"
2
+ VERSION = "2.17.7"
3
3
  end
@@ -38,7 +38,7 @@ module Sidekiq
38
38
  end
39
39
 
40
40
  get "/workers" do
41
- erb :index
41
+ erb :workers
42
42
  end
43
43
 
44
44
  get "/queues" do
@@ -49,21 +49,9 @@ module Sidekiq
49
49
 
50
50
  def workers
51
51
  @workers ||= begin
52
- to_rem = []
53
- workers = Sidekiq.redis do |conn|
54
- conn.smembers('workers').map do |w|
55
- msg = conn.get("worker:#{w}")
56
- msg ? [w, Sidekiq.load_json(msg)] : (to_rem << w; nil)
57
- end.compact.sort { |x| x[1] ? -1 : 1 }
52
+ Sidekiq::Workers.new.tap do |w|
53
+ w.prune
58
54
  end
59
-
60
- # Detect and clear out any orphaned worker records.
61
- # These can be left in Redis if Sidekiq crashes hard
62
- # while processing jobs.
63
- if to_rem.size > 0
64
- Sidekiq.redis { |conn| conn.srem('workers', to_rem) }
65
- end
66
- workers
67
55
  end
68
56
  end
69
57
 
@@ -362,6 +362,22 @@ class TestApi < Sidekiq::Test
362
362
  assert_equal 'default', y['queue']
363
363
  assert_equal Time.now.year, DateTime.parse(z).year
364
364
  end
365
+
366
+ s = '12346'
367
+ data = Sidekiq.dump_json({ 'payload' => {}, 'queue' => 'default', 'run_at' => (Time.now.to_i - 2*60*60) })
368
+ Sidekiq.redis do |c|
369
+ c.multi do
370
+ c.sadd('workers', s)
371
+ c.set("worker:#{s}", data)
372
+ c.set("worker:#{s}:started", Time.now.to_s)
373
+ c.sadd('workers', '123457')
374
+ end
375
+ end
376
+
377
+ assert_equal 3, w.size
378
+ count = w.prune
379
+ assert_equal 1, w.size
380
+ assert_equal 2, count
365
381
  end
366
382
 
367
383
  it 'can reschedule jobs' do
@@ -6,7 +6,7 @@
6
6
  <th><%= t('Arguments') %></th>
7
7
  <th><%= t('Started') %></th>
8
8
  </thead>
9
- <% workers.each_with_index do |(worker, msg), index| %>
9
+ <% workers.each_with_index do |(worker, msg, run_at), index| %>
10
10
  <tr>
11
11
  <td><%= worker %></td>
12
12
  <td>
@@ -16,7 +16,7 @@
16
16
  <td>
17
17
  <div class="args"><%= display_args(msg['payload']['args']) %></div>
18
18
  </td>
19
- <td><%= relative_time(msg['run_at'].is_a?(Numeric) ? Time.at(msg['run_at']) : Time.parse(msg['run_at'])) %></td>
19
+ <td><%= relative_time(run_at.is_a?(String) ? DateTime.parse(run_at) : run_at) %></td>
20
20
  </tr>
21
21
  <% end %>
22
22
  </table>
File without changes
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.17.6
4
+ version: 2.17.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mike Perham
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-02-19 00:00:00.000000000 Z
11
+ date: 2014-02-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: redis
@@ -310,7 +310,6 @@ files:
310
310
  - web/views/_summary.erb
311
311
  - web/views/_workers.erb
312
312
  - web/views/dashboard.erb
313
- - web/views/index.erb
314
313
  - web/views/layout.erb
315
314
  - web/views/queue.erb
316
315
  - web/views/queues.erb
@@ -318,6 +317,7 @@ files:
318
317
  - web/views/retry.erb
319
318
  - web/views/scheduled.erb
320
319
  - web/views/scheduled_job_info.erb
320
+ - web/views/workers.erb
321
321
  homepage: http://sidekiq.org
322
322
  licenses:
323
323
  - LGPL-3.0