<html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:w="urn:schemas-microsoft-com:office:word" xmlns:m="http://schemas.microsoft.com/office/2004/12/omml" xmlns="http://www.w3.org/TR/REC-html40">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=us-ascii">
<meta name="Generator" content="Microsoft Word 14 (filtered medium)">
<style><!--
/* Font Definitions */
@font-face
        {font-family:Calibri;
        panose-1:2 15 5 2 2 2 4 3 2 4;}
@font-face
        {font-family:Georgia;
        panose-1:2 4 5 2 5 4 5 2 3 3;}
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
        {margin:0cm;
        margin-bottom:.0001pt;
        font-size:11.0pt;
        font-family:"Calibri","sans-serif";
        mso-fareast-language:EN-US;}
a:link, span.MsoHyperlink
        {mso-style-priority:99;
        color:blue;
        text-decoration:underline;}
a:visited, span.MsoHyperlinkFollowed
        {mso-style-priority:99;
        color:purple;
        text-decoration:underline;}
p
        {mso-style-priority:99;
        mso-margin-top-alt:auto;
        margin-right:0cm;
        mso-margin-bottom-alt:auto;
        margin-left:0cm;
        font-size:12.0pt;
        font-family:"Times New Roman","serif";}
span.EmailStyle17
        {mso-style-type:personal-compose;
        font-family:"Calibri","sans-serif";
        color:windowtext;}
.MsoChpDefault
        {mso-style-type:export-only;
        font-family:"Calibri","sans-serif";
        mso-fareast-language:EN-US;}
@page WordSection1
        {size:612.0pt 792.0pt;
        margin:72.0pt 72.0pt 72.0pt 72.0pt;}
div.WordSection1
        {page:WordSection1;}
/* List Definitions */
@list l0
        {mso-list-id:1701777207;
        mso-list-template-ids:-1337588872;}
ol
        {margin-bottom:0cm;}
ul
        {margin-bottom:0cm;}
--></style><!--[if gte mso 9]><xml>
<o:shapedefaults v:ext="edit" spidmax="1026" />
</xml><![endif]--><!--[if gte mso 9]><xml>
<o:shapelayout v:ext="edit">
<o:idmap v:ext="edit" data="1" />
</o:shapelayout></xml><![endif]-->
</head>
<body lang="EN-GB" link="blue" vlink="purple">
<div class="WordSection1">
<p style="line-height:19.2pt"><span style="font-family:"Georgia","serif";color:#333333">Hi All,<o:p></o:p></span></p>
<p style="line-height:19.2pt"><span style="font-family:"Georgia","serif";color:#333333">This is a copy of
<a href="http://mikehadlow.blogspot.com/2011/07/easynetq-how-should-messaging-client.html">
a blog post I’ve just written</a>. I was wondering if anyone on the group had any good suggestions for error handling strategies?<o:p></o:p></span></p>
<p style="line-height:19.2pt"><span style="font-family:"Georgia","serif";color:#333333"><a href="https://github.com/mikehadlow/EasyNetQ">EasyNetQ</a> is my simple .NET API for RabbitMQ.<o:p></o:p></span></p>
<p style="line-height:19.2pt"><span style="font-family:"Georgia","serif";color:#333333">I’ve started thinking about the best patterns for implementing error handling in EasyNetQ. One of the aims of EasyNetQ is to remove as many infrastructure concerns from
the application developer as possible. This means that the API should correctly handle any exceptions that bubble up from the application layer.
<o:p></o:p></span></p>
<p style="line-height:19.2pt"><span style="font-family:"Georgia","serif";color:#333333">One of the core requirements is that we shouldn’t lose messages when the application throws. The question then becomes: where should the message, that the application was
consuming when it threw, go? There seem to be three choices:<o:p></o:p></span></p>
<ol start="1" type="1">
<li class="MsoNormal" style="color:#333333;mso-margin-top-alt:auto;mso-margin-bottom-alt:auto;line-height:19.2pt;mso-list:l0 level1 lfo1">
<span style="font-family:"Georgia","serif"">Put the failed message back on the queue it was consumed from.
<o:p></o:p></span></li><li class="MsoNormal" style="color:#333333;mso-margin-top-alt:auto;mso-margin-bottom-alt:auto;line-height:19.2pt;mso-list:l0 level1 lfo1">
<span style="font-family:"Georgia","serif"">Put the failed message on an error queue.
<o:p></o:p></span></li><li class="MsoNormal" style="color:#333333;mso-margin-top-alt:auto;mso-margin-bottom-alt:auto;line-height:19.2pt;mso-list:l0 level1 lfo1">
<span style="font-family:"Georgia","serif"">A combination of 1 and 2.<o:p></o:p></span></li></ol>
<p style="line-height:19.2pt"><strong><span style="font-family:"Georgia","serif";color:#333333">Option 1</span></strong><span style="font-family:"Georgia","serif";color:#333333"> has the benefit that it’s the out-of-the-box behaviour of AMQP. In the case of
EasyNetQ, I would simply catch any exceptions, log them, and just send a noAck command back to RabbitMQ. Rabbit would put the message at the back of the queue and then resend it when it got to the front.<o:p></o:p></span></p>
<p style="line-height:19.2pt"><span style="font-family:"Georgia","serif";color:#333333">Another advantage of this technique is that it gives competing consumers the opportunity to process the message. If you have more than one consumer on a queue, Rabbit will
send the messages to them in turn, so this is out-of-the-box.<o:p></o:p></span></p>
<p style="line-height:19.2pt"><span style="font-family:"Georgia","serif";color:#333333">The drawback of this method is that there’s the possibility of the queue filling up with failed messages. The consumer would just be cycling around throwing exceptions and
any messages that it might be able to to consume would be slowed down by having to wait their turn amongst a long queue of failed messages.<o:p></o:p></span></p>
<p style="line-height:19.2pt"><span style="font-family:"Georgia","serif";color:#333333">Another problem is that it’s difficult to manually inspect the messages and selectively delete or retry them.<o:p></o:p></span></p>
<p style="line-height:19.2pt"><strong><span style="font-family:"Georgia","serif";color:#333333">Option 2</span></strong><span style="font-family:"Georgia","serif";color:#333333"> is harder to implement. I would have to catch exceptions, log them and then write
the message to an error queue. I would need to write an error queue consumer to store the messages in a database. I would then need to provide the user with some way to inspect the messages alongside the error that caused them to arrive in the error queue
so that they could make a ignore/retry decision.<o:p></o:p></span></p>
<p style="line-height:19.2pt"><span style="font-family:"Georgia","serif";color:#333333">I could also implement some kind of wait-and-retry function on the error queue, but that would also add additional complexity.<o:p></o:p></span></p>
<p style="line-height:19.2pt"><span style="font-family:"Georgia","serif";color:#333333">It has the advantage that the original queue remains clear of failing messages. Failed messages and the error condition that caused the failure can be inspected together,
and failed messages can be manually ignored or retried. <o:p></o:p></span></p>
<p style="line-height:19.2pt"><span style="font-family:"Georgia","serif";color:#333333">With the failed messages sitting in a database, it would also be simple to create a mechanism where those messages could be replayed on a developer machine to aid in debugging.<o:p></o:p></span></p>
<p style="line-height:19.2pt"><strong><span style="font-family:"Georgia","serif";color:#333333">A combination of 1 and 2</span></strong><span style="font-family:"Georgia","serif";color:#333333">. I’m moving towards thinking that a combination of 1 & 2 might
be the best strategy. When a message fails initially, we simply noAck it and it goes back to the queue. AMQP provides a Redelivered flag, so when the messages is consumed a second time we can be aware that it’s a retry. Unfortunately there doesn’t seem to
be a retry count in AMQP, so the best we can do is allow for a single retry. This has the benefit that it gives a competing consumer a chance to process the message.<o:p></o:p></span></p>
<p style="line-height:19.2pt"><span style="font-family:"Georgia","serif";color:#333333">After the single retry we fall back to
<strong><span style="font-family:"Georgia","serif"">Option 2</span></strong>. The message is passed to the error queue on the second failure.<o:p></o:p></span></p>
<p style="line-height:19.2pt"><span style="font-family:"Georgia","serif";color:#333333">I would be very interested in hearing how other people have implemented error handling with AMQP/RabbitMQ.<o:p></o:p></span></p>
<p style="line-height:19.2pt"><span style="font-family:"Georgia","serif";color:#333333">Many thanks<o:p></o:p></span></p>
<p style="line-height:19.2pt"><span style="font-family:"Georgia","serif";color:#333333">Mike<o:p></o:p></span></p>
<p class="MsoNormal"><o:p> </o:p></p>
</div>
<br>
<font face="Arial" color="Black" size="3">15below Limited: Company registered in England and Wales No 3945289<br>
Registered Office: Lyndean House, 43-46 Queens Road, Brighton BN1 3XB, United Kingdom<br>
<br>
15below Australia Pty Limited: ABN 25 132 716 379<br>
Level 50, 120 Collins Street, Melbourne, Victoria 3000, Australia<br>
<br>
Please think about the environment before printing this email.<br>
<br>
************************************************************************<br>
This email and any attachments may be confidential and/or legally privileged and are solely for the use of the intended recipient. If you have received this email in error please contact the sender. Any views or opinions expressed within this e-mail are solely
those of the sender, and do not necessarily represent those of 15below unless otherwise specifically stated. Although 15below has taken every reasonable precaution to ensure that any attachment to this e-mail has been checked for viruses, it is strongly recommended
that you carry out your own virus check before opening any attachment, as we cannot accept liability for any damage sustained as a result of software virus infection.<br>
</font>
</body>
</html>