0

Can message become poisoned if it's non-transactional?

The documentation seems to imply not, but I'm not finding a direct statement one way or the other.

InteXX
  • 6,135
  • 6
  • 43
  • 80

1 Answers1

2

Yes, it's possible, in some circumstances.

Poison message is a message which stays on top of a queue, preventing others to come through. Now, what makes transactional messages to go poisoned? It's when we roll back transaction and message goes back where it was before, right on the top of the queue. So it's not something about message itself (at least not directly), but a consequence of how we process messages and what we do when that processing fails, i.e. perform a rollback.

If queue is non-transactional, and we "Receive" message from the top of the queue it's irreversible. There's no rollback which would put message back on that top position. If we want to put that message back to queue to be retried later, all we can do is send a copy of original message. And MSMQ Send puts it at the end of the queue. So it can't block other messages.

There is one case when this doesn't apply, and that's if we play with message priority and send it back with higher priority than the rest of the queue. That would put it back on the top and create poison message scenario.

Another way is if our processing consists of "Peek" (which doesn't remove message), followed by "Receive" if processing is ok. If processing fails between Peek and Receive, message would stay on the top of the queue.

So, yes, it's possible to have poison messages with non-transactional messages, but only if do things in specific way.

Dejan Grujić
  • 402
  • 2
  • 6
  • `If processing fails between Peek and Receive, message would stay on the top of the queue.` Hm, that's exactly what I'm doing. I might instead `Receive()`, and then put it back (with same priority) if processing fails—in this case sending to a WCF service. What would you suggest? – InteXX May 02 '18 at 15:26
  • That's ok. There is a possibility of message loss if your process fails after Receive and before processing is completed. I would you turn on journaling for that queue, and all received messages will end up in journal, so at least you won't lose anything. – Dejan Grujić May 02 '18 at 19:56
  • Although this won't block other incoming messages, retried messages could show up again and again. You can put some "retry counter" in a message if you want to stop retries after let's say 10 retries and notify someone to check it. It's easier if you put that counter in message's Extension, or "App specific" fields, but you can modify body as well. – Dejan Grujić May 02 '18 at 20:05
  • `There is a possibility of message loss if your process fails after Receive and before processing is completed.` Aha! Gotcha covered there too :-) Upon a successful queue `Send()` a `JSON.NET`-serialized text file is placed in a log folder on the file system, to be deleted only after a successful WCF `Send()`. I might eventually end up doing something with a SQL insertion, too, as an extra backup. This journaling feature looks interesting, but it seems tricky to decide how often to empty out that bucket. Caution is certainly the better part of valor there. – InteXX May 03 '18 at 05:51
  • `You can put some "retry counter" in a message if you want to stop retries after let's say 10 retries and notify someone to check it.` Good idea, I'll do that. `It's easier if you put that counter in message's Extension, or "App specific" fields...` Good tip, I'll check it out. – InteXX May 03 '18 at 05:53