Publish failure event when a message is moved to the error queue

Hi,

I am using NServiceBus (latest) with SQL Server everything…
I have what I believe to be a reasonably simple question - though my process or understanding may be a bit off kilter, so some suggestions are welcome.

What I would like to achieve is for a failed handler to publish an event prior to the message being sent to the message queue. I had this in a try/catch inside the handler where I was using the current context to publish the event and then re-throw the exception, but obviously then the published event gets rolled back, so the failure is never noticed. And I would also get an event per retry which isn’t ideal either.

Does the answer lie in a behaviour? Is there some other way to have an event published prior to a message heading to the error queue?

Thanks.

Hi Sean, you have a few options here:

  1. You can subscribe to the OnMessageSentToErrorQueue event and send/publish from there.
    var endpointConfiguration = new EndpointConfiguration("MyEndpoint");
    endpointConfiguration.UseTransport<LearningTransport>();

    IMessageSession messageSession = null;

    endpointConfiguration.Recoverability().Delayed(s => s.NumberOfRetries(0));
    endpointConfiguration.Recoverability()
        .Failed(s => s.OnMessageSentToErrorQueue(fm =>
    {
        var options = new SendOptions();

        options.RequiredImmediateDispatch();//to make sure the send operation doesn't participate in the receive transaction
        options.SetDestination("SomeOtherEndpoint");
        return messageSession.Send(new ReportThatMessageFailed
        {
            Reason = fm.Exception.Message
        }, options);
    }));

    messageSession = await Endpoint.Start(endpointConfiguration)
        .ConfigureAwait(false);

Note the call to RequiredImmediateDispatch to make sure that the operation doesn’t enlist in the current receive transaction to make sure that it gets sent our no matter what.

  1. Subscribe to the MessageFailed event from ServiceControl, see Using ServiceControl Events • ServiceControl Contracts • Particular Docs

  2. Depending on the business requirements potentially use a saga to control the retry behaviour and report various statuses back to other endpoints. See Sagas • NServiceBus • Particular Docs

Can you share some more details on why you need to report that the message was moved to the error queue to other endpoints?

Cheers,

Andreas

Thanks for the quick reply Andreas. I think option 1. is exactly what I’m looking for.

A bit of background - we’ve been using NServiceBus for a good few years on MSMQ, but we are moving forward with .Net Core now and there are a few migration issues that we are facing. This has driven us to use SQL transport and native .Net Core DI.

The migration is a step at a time and the current functionality that I am replacing is to post to MS Teams on failure (this was before Service Pulse etc. became more affordable for a small project like ours). We have an endpoint subscribed to that event that will do this.

Ultimately we will look to taking advantage of Service Control etc, but for the time being I think option 1 will suffice.

Thankks again.

Hi Sean, based on the description of your use case I would recommend you to go for option 2. That allows you to deploy a single endpoint that listens to all failed messages from all endpoints and handle them (send the message to teams), instead of replicating this logic in every endpoint you deploy.
Just my 2 cents…

Hi Marc,

Thanks for the input and I certainly agree with you there. At the moment we are dynamically loading an assemby per endpoint and the endpoints inherit from a base class where this is done. So from a dev point of view the logic is in a single place - though does get deployed multiple times.

I will soon have the time to start looking at the ServiceControl offering and other options now available to us and can then remove that code if/when we get that set up.

Thanks again,
Sean

Hi Andreas,

Could you please explain how we can inject messagSession when the endpoint is hosted as Windows Service?

Thanks,
Adithya

Are you using the generic host to host your windows service?

Yes Andreas. We are using Generic Host

Then injecting the session in the same way as explained should work as described in Publish failure event when a message is moved to the error queue - #2 by andreasohlund

Just put the code in the call to UseNServiceBus(...), see Endpoint hosting with the Generic Host • NServiceBus Samples • Particular Docs for more details.

Does that work for you? (Or are you referring to injecting the IMessageSession somewhere else?)