Skip to content

Instantly share code, notes, and snippets.

@tbuehlmann
Last active February 6, 2019 19:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tbuehlmann/428308f5f0201fbf4b7833e64177e433 to your computer and use it in GitHub Desktop.
Save tbuehlmann/428308f5f0201fbf4b7833e64177e433 to your computer and use it in GitHub Desktop.
# lib/sidekiq/middleware/server/retry_jobs_without_exception.rb
module Sidekiq
RetryWithoutException = Class.new(StandardError)
module Middleware
module Server
class RetryJobsWithoutException < RetryJobs
def call(worker, msg, queue)
begin
yield
rescue RetryWithoutException => exception
attempt_retry(worker, msg, queue, exception) if msg['retry']
end
end
private
# Original: https://github.com/mperham/sidekiq/blob/v4.1.3/lib/sidekiq/middleware/server/retry_jobs.rb#L88-L137
#
# This method overrides the original method with the only change being that after adding
# the job as a retry, it will _not_ raise an exception.
def attempt_retry(worker, msg, queue, exception)
max_retry_attempts = retry_attempts_from(msg['retry'], @max_retries)
msg['queue'] = if msg['retry_queue']
msg['retry_queue']
else
queue
end
# App code can stuff all sorts of crazy binary data into the error message
# that won't convert to JSON.
m = exception.message.to_s[0, 10_000]
if m.respond_to?(:scrub!)
m.force_encoding('utf-8')
m.scrub!
end
msg['error_message'] = m
msg['error_class'] = exception.class.name
count = if msg['retry_count']
msg['retried_at'] = Time.now.to_f
msg['retry_count'] += 1
else
msg['failed_at'] = Time.now.to_f
msg['retry_count'] = 0
end
if msg['backtrace'] == true
msg['error_backtrace'] = exception.backtrace
elsif !msg['backtrace']
# do nothing
elsif msg['backtrace'].to_i != 0
msg['error_backtrace'] = exception.backtrace[0...msg['backtrace'].to_i]
end
if count < max_retry_attempts
delay = delay_for(worker, count, exception)
logger.debug { "Failure! Retry #{count} in #{delay} seconds" }
retry_at = Time.now.to_f + delay
payload = Sidekiq.dump_json(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.
retries_exhausted(worker, msg, exception)
end
# raise exception
end
end
end
end
end
# config/initializers/sidekiq.rb
if Sidekiq::VERSION >= '4.1' && Sidekiq::VERSION < '5'
Sidekiq.configure_server do |config|
config.server_middleware do |chain|
chain.insert_before Sidekiq::Middleware::Server::RetryJobs, Sidekiq::Middleware::Server::RetryJobsWithoutException
end
end
end
# app/jobs/some_job.rb
class SomeJob
include Sidekiq::Worker
sidekiq_options queue: :some_queue, retry: 8, backtrace: false
def perform
# …
raise Sidekiq::RetryWithoutException
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment