Search code examples
rubyaws-sdksidekiqshoryuken

Customizing retry delays with Amazon SQS from Shoryuken (ruby)


I am migrating a background job processing service made with sidekiq to shoryuken, which is based on Amazon SQS. With sidekiq you can customize the retries pattern by using sidekiq_retry_in:

class WorkerWithCustomRetry
    include Sidekiq::Worker
    sidekiq_options :retry => 5

    sidekiq_retry_in do |count|
        retry_count(count)
    end

    def self.retry_count(count)
    ...
    end
end

where, in my case, retry_countreturns the delay for the next retry based on external configuration. With shoryuken retries are yielded to SQS which handle retries automatically as long as the message is not deleted by the consumer application. However with shoryuken you can change the delay by using retry_intervals but documentation only explains how to set fixed values:

class MyWorker
    include Shoryuken::Worker

    shoryuken_options queue: 'default', retry_intervals: [360, 1200, 3600] # 5.minutes, 20.minutes and 1.hour

end

I need to customize the delay for retries the same way as with sidekiq, using a retry_count method which returns different values depending on external data. Is this possible or does exist a workaround to do that with shoryuken?


Solution

  • Currently Shoryuken only supports fixed values for exponential backoff, but you can submit a PR changing ExponentialBackoffRetry with:

    # https://github.com/phstc/shoryuken/blob/290b1cb4c4c40f34881d7f7b7a3beda949099cf5/lib/shoryuken/middleware/server/exponential_backoff_retry.rb#L11
    
    retry_intervals = worker.class.get_shoryuken_options['retry_intervals']
    
    retry_intervals = if retry_intervals.respond_to? :call
                        retry_intervals.call(worker, queue, sqs_msg, body)
                      else
                        Array(retry_intervals)
                      end
    

    So you will be able to use a proc or fixed values to set retry_intervals, i.e.:

    class MyWorker
      include Shoryuken::Worker
    
      shoryuken_options queue: 'default', 
        retry_intervals: -> (worker, queue, sqs_msg, body) { worker.your_method(...) }
    end
    

    OR you can remove the default ExponentialBackoffRetry and add yours:

    Shoryuken.configure_server do |config|
      config.server_middleware do |chain|
        chain.remove Middleware::Server::ExponentialBackoffRetry
        chain.add YourExponentialBackoffRetry
      end
    end
    

    But keep in mind that SQS does not officially support exponential backoff, it's something implemented in Shoryuken using the Visibility Timeout, which can extended to a maximum of 12 hours.

    https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_ChangeMessageVisibility.html

    You can continue to call ChangeMessageVisibility to extend the visibility timeout to a maximum of 12 hours. If you try to extend beyond 12 hours, the request will be rejected.