CruelIO
CruelIO

Reputation: 18624

NServiceBus events ends in timeout queue

I'm handling the event with the HandleMyEvent class

public class HandleMyEvent :  IHandleMessages<MyEvent>
{

    private readonly IBus _bus;
    private readonly IWorkorker _workerTools;


    public HandleProductInstanceEvent( IBus bus, IWorkorker worker)
    {
        _bus = bus;
        _workerTools = worker;

    }

    public void Handle(IProductInstancesUpdatedEvent message)
    {
        var worker = new myWorker(_bus, _worker);
        myWorker.DoWork(message.data);
    }
}

myWorker.DoWork can run for up to 5 minutes before its done.

When the publisher sends a single "MyEvent" it seems like the handler recieves 5 events before the message ends in the timeouts queue, I guess that it retries 5 times, before giving up.

In the logfile i can find this entry

NServiceBus.Unicast.Queuing.FailedToSendMessageException: Failed to send message to address: My.Bus.Service@MyServer ---> System.Messaging.MessageQueueException: Cannot enlist the transaction.
   at System.Messaging.MessageQueue.SendInternal(Object obj, MessageQueueTransaction internalTransaction, MessageQueueTransactionType transactionType)
   at NServiceBus.Transports.Msmq.MsmqMessageSender.Send(TransportMessage message, Address address) in c:\work\3206e2123f54fce4\src\NServiceBus.Core\Transports\Msmq\MsmqMessageSender.cs:line 59

Why am I getting this error?

Upvotes: 1

Views: 1292

Answers (1)

janovesk
janovesk

Reputation: 1138

You are getting that error because handling a MSMQ message in NServiceBus, by default, runs in a transaction with a timeout of 1 minute.

Once you pass the transaction timeout any new operations, like sending a message or storing something in a database, will fail with

Cannot enlist the transaction.

You should either increase your transaction timeout to something more than the expected processing time or turn off transactions on this endpoint.

Note that a message handler running for 5 minutes is a long time. Having transactions, and thus locks, against transactional resources for such long periods of time is not optimal.

Once the message handling fails, the transaction rolls back, putting the message back on the queue. It is then retried for however many first level retry attempts you have configured. Most likely 5 in your scenario. After that, it is moved to second level retries.

The .timeout queue is the input queue for timeout manager responsible for handling second level retries. If the message is not immediately picked up from this queue, you are not running a timeout manager on that endpoint.

Upvotes: 3

Related Questions