I've read a lot of blogs and books about event driven messaging between microservices or bounded contexts to share state or react to events. Most examples implement a command handler like the following snippet. Which is actually a simplified snippet from the book 'Patterns, Principles, and Practices of Domain-Driven Design'.
public void Handle(PlaceOrder message)
{
var orderId = Database.SaveOrder(
message.ProductIds, message.UserId, message.ShippingTypeId
);
// what if something goes wrong here?
var orderCreatedEvent = new OrderCreated
{
OrderId = orderId,
UserId = message.UserId,
ProductIds = message.ProductIds,
ShippingTypeId = message.ShippingTypeId,
TimeStamp = DateTime.Now,
Amount = CalculateCostOf(message.ProductIds)
};
Bus.Publish(orderCreatedEvent);
}
The snippet seems incomplete since storing the order could succeed without sending the message. I know I could use the transaction outbox pattern, which adds additional cost of storing messages in a table and to have a worker periodically check the table and send missed messages. Another approach is using event sourcing, but that seems like overkill just to solve the issue of reliable messaging. So I'm wondering if there are alternatives such as a transaction which works on the bus and the database together? Or should the Database.SaveOrder()
be idempotent somehow so I could always repeat the whole procedure?
Out of all the possible solutions you have, the transactional outbox pattern is probably the easiest to implement and maintain.
Distributed transactions are complex to maintain, especially in cases where the coordinator node fails. In addition, I think the most popular tools like Kafka actually don't support distributed transactions.
If your database can tolerate extra load, then the outbox pattern is the way to go.
You can read a more in-depth analysis of the pattern from here