Class: Sidekiq::Middleware::Server::RetryJobs

Inherits:
Object
  • Object
show all
Includes:
Retry, Util
Defined in:
lib/sidekiq/middleware/server/retry_jobs.rb

Overview

Automatically retry jobs that fail in Sidekiq. A message looks like:

{ 'class' => 'HardWorker', 'args' => [1, 2, 'foo'] }

We'll add a bit more data to the message to support retries:

* 'queue' - the queue to use
* 'retry_count' - number of times we've retried so far.
* 'error_message' - the message from the exception
* 'error_class' - the exception class
* 'failed_at' - the first time it failed
* 'retried_at' - the last time it was retried

We don't store the backtrace as that can add a lot of overhead to the message and everyone is using Airbrake, right?

Constant Summary

Constants included from Retry

Retry::DELAY, Retry::MAX_COUNT, Retry::POLL_INTERVAL

Instance Method Summary collapse

Methods included from Util

#constantize, logger, #logger, logger=, #process_id, #redis, #watchdog

Instance Method Details

#call(worker, msg, queue) ⇒ Object


27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/sidekiq/middleware/server/retry_jobs.rb', line 27

def call(worker, msg, queue)
  yield
rescue => e
  raise unless msg['retry']

  msg['queue'] = queue
  msg['error_message'] = e.message
  msg['error_class'] = e.class.name
  count = if msg['retry_count']
    msg['retried_at'] = Time.now.utc
    msg['retry_count'] += 1
  else
    msg['failed_at'] = Time.now.utc
    msg['retry_count'] = 0
  end

  if count <= MAX_COUNT
    delay = DELAY.call(count)
    logger.debug { "Failure! Retry #{count} in #{delay} seconds" }
    retry_at = Time.now.to_f + delay
    payload = MultiJson.encode(msg)
    Sidekiq.redis do |conn|
      conn.zadd('retry', retry_at.to_s, payload)
    end
  else
    # Goodbye dear message, you (re)tried your best I'm sure.
    logger.debug { "Dropping message after hitting the retry maximum: #{msg}" }
  end
  raise
end