Comments on: Error Handling in MassTransit Consumers https://looselycoupledlabs.com/2014/07/error-handling-in-masstransit-consumers/ **ARCHIVED** A Blog Loosely Related to System Architecture by David Prothero **ARCHIVED** Sat, 29 Jun 2019 14:03:00 +0000 hourly 1 https://wordpress.org/?v=5.8.6 By: Tristan Hen https://looselycoupledlabs.com/2014/07/error-handling-in-masstransit-consumers/#comment-283 Sat, 29 Jun 2019 14:03:00 +0000 http://looselycoupledlabs.com/?p=115#comment-283 In a publish / subscribe scenario: if I have 2 consumers and the message is poison: how many error queues will I have ? One per consumer ?

]]>
By: Marcus Widblom https://looselycoupledlabs.com/2014/07/error-handling-in-masstransit-consumers/#comment-65 Thu, 17 Dec 2015 11:11:00 +0000 http://looselycoupledlabs.com/?p=115#comment-65 Great post David, this works like a charm.

I took the opportunity and wrote an extension method to MassTransit IConsumeContext:


public static void ConsumeWithRetry(this IConsumeContext envelope, Dictionary retryPolicy, Action action, ILog logger = null, string exceptionLogMessage = "") where TMessage : class, new() where TException : Exception
{
var retryDelay = 0;
int.TryParse(envelope.Headers["retry-delay-seconds"], out retryDelay);
var nextRetryDelay = retryPolicy[retryDelay];
var sleepAndRepublish = false;

try
{
action();
}
catch (TException ex)
{
if (logger != null && !string.IsNullOrEmpty(exceptionLogMessage))
logger.Error(exceptionLogMessage + " Exception message: " + ex.Message);

if (nextRetryDelay > -1)
{
if (logger != null)
logger.Info(string.Format("Sleeping consumer for {0} seconds and retrying...", nextRetryDelay));

sleepAndRepublish = true;
}
else
{
throw;
}
}

if (sleepAndRepublish)
{
Thread.Sleep(nextRetryDelay * 1000);
envelope.Bus.Publish(envelope.Message, x =>
{
x.SetHeader("retry-delay-seconds", nextRetryDelay.ToString());
x.SetDeliveryMode(MassTransit.DeliveryMode.Persistent);
});
}
}

Cheers!

]]>
By: Rafal Gwizdala https://looselycoupledlabs.com/2014/07/error-handling-in-masstransit-consumers/#comment-14 Wed, 06 Aug 2014 07:34:00 +0000 http://looselycoupledlabs.com/?p=115#comment-14 In reply to dprothero.

Of course, everything that works is good.

]]>
By: dprothero https://looselycoupledlabs.com/2014/07/error-handling-in-masstransit-consumers/#comment-13 Tue, 05 Aug 2014 22:59:00 +0000 http://looselycoupledlabs.com/?p=115#comment-13 In reply to Rafal Gwizdala.

“otherwise you’ll quickly run out of available threads and processing will stop”

Of course it will. That’s why I discuss this in the section “Did You Seriously Just Block the Consumer Thread?”

It all depends on your use case. If you have a service dedicated to processing one type of message and the inability to process those messages because of an external dependency being down occurs, there’s no reason to be concerned that it will stop all processing. That’s a good thing. No processing can occur anyway, why let the process spin its wheels?

There will be cases where it’s not a good thing, of course.

If you’ve got an error that will occur with only a few messages, but most will be OK, then this is definitely not the way to handle it. You will want to use a scheduler like Quartz and the MassTransit.Quartz integration project. Or you can roll your own and use a database or perhaps another queue in RabbitMQ.

I just don’t believe in adding the additional complexity if it isn’t necessary. I also don’t believe there’s a “one right way” to do anything… it always depends on your use case and related factors. “Only a Sith deals in absolutes.” 😛

Thanks for the comment!

]]>
By: Rafal Gwizdala https://looselycoupledlabs.com/2014/07/error-handling-in-masstransit-consumers/#comment-12 Tue, 05 Aug 2014 20:19:00 +0000 http://looselycoupledlabs.com/?p=115#comment-12 Hi there,
You touched an interesting subject
However, blocking the consumer thread for the duration of retry delay is imho unacceptable. This is only good if
a) the delay is no more than few seconds
b) you don’t have too many failing messages
otherwise you’ll quickly run out of available threads and processing will stop
This is basically re-scheduling message to be processed later and it’s imho better to do it using a database – put the message into a database, specify the delivery time and let some daemon publish it when the time comes. This way you can schedule an unlimited number of messages without performance penalty. And this functionality has many other uses beyond retrying failed messages – for example, you can implement all kinds of timeouts with it.

]]>
By: dprothero https://looselycoupledlabs.com/2014/07/error-handling-in-masstransit-consumers/#comment-10 Tue, 29 Jul 2014 13:34:00 +0000 http://looselycoupledlabs.com/?p=115#comment-10 In reply to udidahan.

Thanks Udi! Great to see the contrasts between NServiceBus and MT. Keep em’ coming!

]]>
By: udidahan https://looselycoupledlabs.com/2014/07/error-handling-in-masstransit-consumers/#comment-9 Tue, 29 Jul 2014 05:32:00 +0000 http://looselycoupledlabs.com/?p=115#comment-9 Thanks for the NServiceBus call-out.

BTW – we also have a graphical tool for monitoring the error queue and sending a message back to be reprocessed.

Incidentally, the approach we recommend is having a single error queue for the entire system as it simplifies monitoring. I can understand why MT went with the approach of having the error queue be “under” the source queue (so that it is clear from which queue it came), but we deal with that by appending a header to the message when we put it in the error queue.

In any case, great blog post!

]]>