0
votes

How can I send a message (or publish an event) when a message runs out of retries and moves to the error queue?

When a request comes into my system, I create a Saga to track it. The Saga sends commands to Handlers to do async work. If the handler fails, I want to both move that command to the error queue (the default behavior) and send a message to the Saga to alert the client that originally requested the work.

I have tried customizing the recoverability behavior to use the Saga as the error queue, which sends the command back but does not get it into the error queue:

recoverability.CustomPolicy((config, context) =>
{
    // invocation of default recoverability policy
    var action = DefaultRecoverabilityPolicy.Invoke(config, context);

    if (action is MoveToError)
    {
        return RecoverabilityAction.MoveToError("SagaEndpoint");
    }

    return action;
});

Another thing I tried was using a Behavior to hook into the Pipeline, but there does not seem to be a a way to override the "move to error queue" step. I can create an IIncomingLogicalMessageContext and try/catch around the await next();, but that triggers for each retry instead of just the final one. I also tried an IOutgoingLogicalMessageContext, but that does not get invoked when a message moves to the error queue. If I missed something, that could be a solution.

I also know I can use a timeout in the Saga to guess when the Handler fails. But I would rather not wait for a timeout if the failure is quick or risk timing out if the work takes longer than expected.

I found this older question that sounds like it's asking the same thing, but the answer is incomplete and uses the older EventHandler Notifications instead of the newer Task-based Notifications. If there is a way to access an IMessageSession or IEndpointInstance from the Notification callback, I think that would work for me as well.

1
Is this what you are looking for? docs.particular.net/nservicebus/recoverability/…Sean Farmar
@SeanFarmar That is what I want, but I need to get an IMessageSession from within those callbacks.Andrew

1 Answers

2
votes

There's not an "easy" way to do that because at the moment when recoverability is happening, any transaction related to the incoming message (this is different for each transport) is in doubt, so you can't really do anything else within the scope of what's going on right at that moment.

Once you start your endpoint, you can cast the IEndpointInstance to an IMessageSession (same thing without things like the Stop method) and then assign that to a place where your "error queue notifier" will be able to find it. Then any operation you do with the IMessageSession will basically be a separate context, disconnected from the processing of the incoming message.

Just understand that if the message is failing processing because of an underlying problem with the queue, that's not going to report correctly. That's why most people would be doing some sort of call to a reporting/diagnostics service in those callbacks.