This is now no longer a critical bug, but something that probably requires looking into or a great big disclaimer somewhere.
I left some debugging code in a handler that was sending more than 100 messages in the production system. What I would have expected would be for the entire handler transaction to fail, but it commited the database changes as expected, and then replayed the message again (and again a few times before I could stop it).
There is a danger message about the maximum size of a message, but not about the number of messages.
When running with Azure Service Bus transport using SendsAtomicWithReceive transport transaction mode, the number of messages cannot exceed 100 messages. When that happens, TransactionContainsTooManyMessages is thrown. Exception text is (quoting):
Azure Service Bus cannot send more than 100 messages in a signle transaction. Reduce number of messages sent out or reduce transport transaction mode.
The inner exception will be of a type MessageTooLargeException thrown by the Azure Service Bus client, and that one will contain the into about message maximum size.
@danielmarbach has raised an issue and I’d encourage to continue there, but there’s something we should clarify - transport transaction mode is a transport only transaction mode. It is not covering business data. Business data participates with transport transactions only when TransactionScope mode is used. Since Azure Service Bus does not support it, business data does not participate in the transport transaction, it’s comitted and then messages are dispatched. Due to larger than allowed number of messages, an exception is thrown. When that happens, transport transaction is reverted, outgoing messages are cancelled and the incoming message is re-delivered / retried.
To sum it up, it works as expected. The documentation might not be very clear, and I would appreciate if you could leave the feedback on the documentation to let us know how can we improve it.
Thanks for this. The documentation is generally of a really good standard, but there are some corner cases that catch you out like this one.
It was a surprise to see a message that had successfully moved through a handler retried. Your API is generally low on surprises so this is definitely one for the documentation.
I don’t really know where I’d put it (maybe on each transport that doesn’t combine the business and transport transactions page?) but your clarification is a bit of a revelation to me, and I’ve been using the produt (albeit with limited exposure to transports) for about 5 years now.
Mind if I ask what transport were you using before?
MSMQ and SQL transports are the only ones that would support transaction sharing between business data and transport.
Azure Service Bus can’t support higher than Sends atomic with Receive mode. Consistency guarantees for this mode are:
This mode has the same consistency guarantees as the Receive Only mode, but additionally it prevents occurrence of ghost messages since all outgoing operations are atomic with the ongoing receive operation.
When Receive Only mode guarantee is
In this mode the receive operation is wrapped in a transport’s native transaction. This mode guarantees that the message is not permanently deleted from the incoming queue until at least one processing attempt (including storing user data and sending out messages) is finished successfully.
Transaction Mode page is definitely a good page to read on transaction mode and what kind of guarantees you will get.