Search code examples
transactionscoperebusretrypolicy

Rebs handler doesnt retry when exception is thrown


I'm using rebus 3.1.5 with rebus.rabbitmq 3.0.0, and rabbitmq.client 4.1.1. I have configured to use simple retry strategy with 2 max delivery attempts. I would like to retry the message in case when an exception is thrown. I don't use the transaction scope. But when an exception is thrown I don't get the message re-delivered again(it is not even in the error queue)

If this is not possible and if I need to configure rebus with HandleMessagesInsideTransactionScope, does it going to put locks my database until I complete the handler work?

thank you very much!

EDIT: This is what the handler looks like:

public Task Handle(SetCreditInfoCommand command) 
{
    return Task.Run(() => {
        var loanApplication = _loanApplicationRepository.Get(command.LoanApplicationId); 
        try { 
            //something that throws an exception here
        }
        catch(Exception ex)
        {
            throw ex;
        }
    });
} 

and this is how the bus is configured:

var bus = Configure.With(adapter)
    .Transport(t => t.UseRabbitMq(connectionString, queueName))
    .Options(b => b.SimpleRetryStrategy(
            maxDeliveryAttempts: 2,
            secondLevelRetriesEnabled: true, 
            errorQueueAddress: queueName + "_error"
    ))
    .Timeouts(t => t.StoreInSqlServer(dbConnection, "RebusTimeouts", false))
    .Start();

IoC.GetContainerBuilder().RegisterInstance(bus).As<IBus>(); 

Solution

  • I don't use the transaction scope

    Good – the transaction scope is only there if you want to group multiple bus operations together OUTSIDE of a Rebus handler, e.g. when handling a web request.

    Everything that happens in a Rebus handler is automatically grouped together and committed as part of the transaction context that spans the handling of the incoming message.

    EDIT: The question author meant System.Trasactions.TransactionScope, which Rebus can automatically apply to message handlers by using the Rebus.TransactionScopes package.

    I originally thought it was RebusTransactionScope, which is Rebus' own scope for managing its own messaging transaction.

    when an exception is thrown I don't get the message re-delivered again(it is not even in the error queue)

    This sounds weird. Do you let the exception bubble out of the message handler?


    I added the code from your comments to your question – it's much easier to read it that way :)

    First off, I suggest you simplify your code by using the async keyword in the method declaration like this:

    public async Task Handle(SetCreditInfoCommand command) 
    {
        // (...)
    } 
    

    Next, I recommend you do now throw ex, because that's not a proper rethrow – it will ruin the stack trace of the ex exception.

    You should

    catch(Exception ex)
    {
        throw;
    }
    

    if you absolutely want to catch the exception. But I really recommend that you do NOT catch exceptions in your Rebus handlers, unless you want to do something with them – in this case, it looks to me like your handler would be better off like this:

    public async Task Handle(SetCreditInfoCommand command) 
    {
        var loanApplication = _loanApplicationRepository.Get(command.LoanApplicationId); 
    
        //something that throws an exception here
    } 
    

    because it's much clearer.

    The second level retries are working fine but the immediate retries are not working

    So it looks like Rebus jumps directly to 2nd level retries? Can you tell me more about how you figured that out?