Domain-Driven Design
Event Sourcing
Exactly once delivery in face of failures
Exactly once delivery
Exactly once processing
"Just make your logic idempotemt"
-- Twitter Trolls
public class ConfirmOrderHandler
: IHandleMessages<ConfirmOrder>
{
public Task Handle(ConfirmOrder msg,
IMessageHandlingContext context)
{
/*business logic*/
context.Publish(evnt);
}
}
System.Messaging.MessageQueueException (0x80004005):
↳ Insufficient resources to perform operation.
↳ at System.Messaging.MessageQueue.SendInternal(Object obj,
↳ MessageQueueTransaction internalTransaction,
↳ MessageQueueTransactionType transactionType)
System.Exception: Channel has been closed: AMQP close-reason,
↳ initiated by Library, code=541, text="Unexpected Exception",
↳ classId=0, methodId=0, cause=System.Net.Sockets.SocketException
↳ A connection attempt failed because the connected party did not
↳ properly respond after a period of time, or established
↳ connection failed because connected host has failed to respond
Persist state✔️
Publish event🔥
Publish event
Persist state
Transaction (Process ID) was deadlocked on lock
↳ resources with another process and has been
↳ chosen as the deadlock victim.
↳ Rerun the transaction.
"Just make your logic idempotemt"
-- Twitter Trolls
Framing the problem
Don't lose messages 🗑️
Apply state change only once 👯♂️
Don't leak non-durable state 👻
If you could add quantity to the order lines
that would be GREAT!
Framing the problem
Don't lose messages 🗑️
Apply state change only once 👯♂️
Don't leak non-durable state 👻
Apply state change only once
"... we want an endpoint to produce observable side-effects equivalent to some execution in which each logical message gets processed exactly-once"
-- Tomasz Masternak
"Just make your logic deterministic"
-- Twitter Trolls
If you could add FirstItemAdded
event
that would be GREAT!
public class AddItemHandler
: IHandleMessages<AddItem>
{
public Task Handle(AddItem message,
IMessageHandlingContext context)
{
/*...*/
if (order.Lines.Count == 1)
{
context.Publish(
new FirstItemAdded(/*...*/));
}
}
}
Receive AddItem 123
✔️
Check if not a duplicate✔️
Add OrderLine
to Order
and persist✔️
Publish ItemAdded
✔️
Count OrderLines
1
Publish FistItemAdded
🔥
Put AddItem 123
back to queue✔️
Receive AddItem 234
✔️
Check if not a duplicate✔️
Add OrderLine
to Order
and persist✔️
Publish ItemAdded
✔️
Count OrderLines
2
Publish FistItemAdded
Receive AddItem 123
✔️
Check if not a duplicate👯♂️
Add OrderLine
to Order
and persist
Publish ItemAdded
✔️
Count OrderLines
2
Publish FistItemAdded
Business logic is executed correctly✔️
Message publishing is based on an incorrect state ❌
Consistent messaging
Re-publish messages based on historic state
Durably store outgoing messages
If you could finally get that code to work
that would be GREAT!
Do you know why are those messages processed in the wrong order?
exactly-once.github.io