Transactional Outbox Pattern
Transactional Outbox Pattern, Why? (part 1)
Background
In microservice and event driven architecture, transactional outbox pattern is crucial to maintain the state of data (or "aggregate" as per Domain Driven Design) in two or more persistent storages, especially when 2 Phase Commit is not available nor desired. You can read an excellent explanation of the pattern here. This article will be divided into two parts, part 1 will discuss why we need it, part 2 will discuss how we can implement it.
In my experience designing solutions with transaction outbox pattern, I have come across multiple similar questions challenging why do we have to do it in such a complex way, and why can't we just reverse the order, use try catch clause, database transaction, etc. Based on those frequent conversations, here is my attempt to explain why we can't solve the problem with ordering, try catch clause or transactions.
Suppose we have a system where we create a person record, which will be stored in postgresqlDB and published to a Kafka topic for other microservices to subscribe and act on it.
1. PostgresqlDB first then Kafka Topic
Summary: save the data to the postgresqlDB table first, catch any errors, if no error then publish the data to the kafka topic
Problem: publishing to kafka could fail right after successfully saving person A to the database, this will result in inconsistency of the data in the system whereby database contains person A but kafka topic doesn't
2. Kafka Topic first then PostgresqlDB
Problem: database save could fail right after successfully publishing to kafka topic, this will result in inconsistency of the data in the system whereby kafka topic contains person A but database doesn't