This was running on Azure Service Bus (SendsAtomicWithReceive) with SQL Server, and everything worked fine. I then changed the transport to Azure Queue Storage (ReceiveOnly), and now we’re losing the last SomeCommand after the saga ends (the saga table is empty, but there’s no SomeCommand on the queue).
Is this expected? If so, why doesn’t it send the outgoing message and await the ACK before completing the saga?
You should complete saga with an explicit message and have a handler for that message that doesn’t do anything else.
The problematic scenario is when sagas are being completed together with sending/publishing outgoing messages. In case of failure after the saga is completed, the outgoing messages may not be dispatched. However, when the incoming message is retried the completed saga is not found, which results in outgoing messages being lost.
This issue can be avoided by:
Enabling the Outbox feature, if supported by the chosen persistence.
Ensure that no outgoing messages will be dispatched by completing the saga from a timeout or sending an explicit command to self.
Replace saga completion with soft delete by setting a flag/timestamp and use some native mechanism of the selected storage to cleanup old saga instances.