Send message to error queue first time

1k views Asked by At

Using NServiceBus 4.3 I want to send a message to the error queue when certain conditions arise.

The scenario is that when I get a message in I check if this message is referring to 1 or more items in our database. If there are multiple references I throw a AmbiguousItemException and catch it. I need to email the person responsible for giving me the correct information. All of that is figured out but I don't want this message to be tried again. Instead I'd rather move it to the error Queue so when we get back the information we need we can add in the nullable property and put the message back into the queue for processing. I've tried using _bus.ForwardCurrentMessageTo("error"), _bus.Send("error", message), _bus.SendLocal(message). The last one basically puts the message in an infinite loop. The code is kind of like this.

public class MoveToErrorQueue
{
    private readonly IBus _bus;

    public MoveToErrorQueue(IBus bus)
    {
        _bus = bus;
    }

    public virtual void Send(ResubmitMessage message)
    {
        message.Foo= -1;
        _bus.Send("error", message);
    }
}

and the code that calls it

        try
        {
            //removed for brevity
        }
        catch (AmbiguousItemException ex)
        {
            Log.Error(ex);
            sendNotificationCommand.FailureMessage = ex.Message;
            _moveToErrorQueue.Send(commandMesage);
        }
        SendNotification(sendScanningNotificationCommand);
2

There are 2 answers

4
Colin Pear On

From what you are describing it sounds like you have a long running business process. This is a candidate for using a Saga. Sagas handle incoming messages like a handler does but the Saga also allows you to track state. So rather than try to kick your message off into an error queue (which is not really a good idea) you can instead set a flag of some type like a boolean or enum on the Saga which will indicate that you received a message that is "referring to 1 or more items in your database" as you put it.

After setting the flag you can then fire off some kind of message to notify you or whoever that an email needs to be sent out to your customer to get updated info (this can probably be automated).

Once you receive the necessary info you can take whatever action is necessary and then send a message back to the Saga telling it to continue with its process and/or mark it as complete and close it out.

You can learn more about Sagas here

2
Simon On

It is possible to plug into the retires API and return a "no retries" number to essentially send certain exceptions to the error queue

http://docs.particular.net/nservicebus/errors/automatic-retries#second-level-retries-custom-retry-policy-exception-based-policy

var retriesSettings = busConfiguration.SecondLevelRetries();
retriesSettings.CustomRetryPolicy(MyCustomRetryPolicy);

The Policy

TimeSpan MyCustomRetryPolicy(TransportMessage transportMessage)
{
    if (transportMessage.ExceptionType() == typeof(MyBusinessException).FullName)
    {
        // Do not retry for MyBusinessException
        return TimeSpan.MinValue;
    }

    if (transportMessage.NumberOfRetries() >= 3)
    {
        return TimeSpan.MinValue;
    }

    return TimeSpan.FromSeconds(5);
}

And a header helper

static class ErrorsHeadersHelper
{
    internal static int NumberOfRetries(this TransportMessage transportMessage)
    {
        string value;
        if (transportMessage.Headers.TryGetValue(Headers.Retries, out value))
        {
            return int.Parse(value);
        }
        return 0;
    }

    internal static string ExceptionType(this TransportMessage transportMessage)
    {
        return transportMessage.Headers["NServiceBus.ExceptionInfo.ExceptionType"];
    }
}