Search code examples
rabbitmqnservicebusretry-logicexponential-backoff

Configuring NServiceBus (with RabbitMQ Transport) for exponential backoff on delayed retries


I'm trying to configure NServiceBus to implement an exponential backoff scheme for delayed retries. For example:

1) on the first failure retry in 2^0 minutes

2) on the second failure retry in 2^1 minutes

3) on the third failure retry in 2^2 minutes

I found an issue on github that seems to indicate that exponential backoff is possible with a Custom Recoverability Policy, but I am not able to determine from Particular's documentation how to achieve that.

Would anyone be able to point me in the right direction for setting up a Custom Recoverability Policy for NServiceBus that would enable exponential backoff for delayed retries?


Solution

  • Edited to incorporate answer from @sabacc's comment

    From my research, NServiceBus does not support exponential backoff out of the box. However, the Custom Recoverability policy allows you to configure the number of immediate and delayed retries as well as the time between delayed retries.

    Since NServiceBus includes the number of delayed deliveries performed within the ErrorContext object as DelayedDeliveriesPerformed, we can incorporate that into the delay calculation on each delay iteration.

    I've provided the code below for the case of a Semi-Transient exception (InternalServerException) that ought to have one immediate and 3 delayed retries in an exponential backoff fashion.

    private RecoverabilityAction RetryPolicy(RecoverabilityConfig config, ErrorContext context)
    {
        var delay = Math.Pow(10, context.DelayedDeliveriesPerformed);
    
        var semiTransientConfiguration = new RecoverabilityConfig(
                 new ImmediateConfig(1), 
                 new DelayedConfig(3, TimeSpan.FromSeconds(delay)),
                 config.Failed);
    
        if (context.Exception is InternalServerException)
        {
            var action = DefaultRecoverabilityPolicy.Invoke(
                         semiTransientConfiguration, context);
        }
    
        return action;
    }