mperham/sidekiq — pull request #1280 by GAV1N (2013-10-25 00:15:26+00:00)
Title: Allow retrying a job even when rescuing an exception

One of our Sidekiq workers often encounters various "transient" errors (timeouts, IO errors, etc). Since the processing usually succeeds after the 2nd or 3rd attempt, we'd like to suppress those exceptions so that they don't hit our exception notification service (BugSnag) until they've been retried a certain number of times. However, we still need Sidekiq to register the job as a failure and schedule it to be retried. We couldn't think of a way to do this with the current Sidekiq::Middleware::Server::RetryJobs instrumentation.

With this PR, our custom middleware accomplishes what we're trying to do:

```ruby
module SidekiqTransientExceptions

class Middleware

def call worker, job, queue
begin
yield
rescue Exception => ex
retries = job['retry_count'] || 0
raise_exception = ex.is_a?(TransientException) ? retries >= TransientException.retry_limit : true

if raise_exception
# exception re-raised by SidekiqTransientExceptions
raise ex
else
# exception silenced by SidekiqTransientExceptions, but job scheduled to be retried
Sidekiq::Middleware::Server::RetryJobs.new.process_retry_exception worker, job, queue, ex
end
end

end

end

end
```

Where the exception originates:

```ruby
class MyWorker

include Sidekiq::Worker
sidekiq_options :retry => 5

class TransientException < Exception
def self.retry_limit ; 3 ; end
end

def perform
begin
some_function! # sometimes raises an IOError, SocketError, Timeout::Error
rescue IOError, SocketError, Timeout::Error => ex
raise TransientException.new(message: ex.message)
end
end
end
```

Of course, if there's a better way to accomplish this then we're all ears :)