Why “Save‑then‑Publish” Isn’t Safe: Solving Distributed Transactions with a Local Outbox
The article explains why the naïve "save‑then‑publish" pattern in message‑driven microservices can cause data inconsistency, analyzes failure scenarios, and presents the local outbox pattern with transactional guarantees and eventual consistency as a robust solution.
Problem with the Simple Save‑then‑Publish Pattern
In a message‑driven microservice, a typical flow is to process a request, insert data into the database, and then publish an event. The naïve pseudo‑code looks like:
var content = processRequest(httpRequest);
var message = prepareMessage(httpRequest);
DB.insert(content);
Message.publish(message);This approach seems straightforward but fails in several cases:
Database insert succeeds while message publishing fails – the database contains data but the event is lost, leading to inconsistency.
Database insert fails after the transaction is committed but before the response is returned – the database may have persisted data while the caller believes the operation failed.
Message publishing succeeds but the subsequent delete of the stored message fails – duplicate events may be sent by a compensation task.
These situations are manifestations of a distributed transaction problem: two independent resources (the database and the message bus) need their operations to be atomic.
Adopting the Local Outbox Pattern
To achieve atomicity without a heavyweight distributed transaction manager, the article proposes using a local outbox table that participates in the same database transaction as the business data.
var content = processRequest(httpRequest);
var message = prepareMessage(httpRequest);
DB.begin();
DB.insert(content);
DB.insert(message); // store message in outbox table
DB.commit();
Message.publish(message);
DB.delete(message); // remove after successful publish
// Compensation task
Executor.execute(new Task() {
public void run() {
while (true) {
var msg = DB.selectMessage();
Message.publish(msg);
DB.delete(msg);
}
}
});Because the message record is written inside the same transaction as the business data, either both succeed or both roll back, guaranteeing consistency. A periodic task scans the outbox for unsent messages and retries publishing, ensuring eventual consistency.
The pattern handles the earlier failure scenarios:
If the database commit succeeds but publishing fails, the outbox retains the message for later retry.
If the database commit fails, the outbox entry never exists, so no stray messages are sent.
If message deletion fails after a successful publish, the retry task may resend the message, which is acceptable as long as downstream consumers are idempotent or the broker (e.g., Kafka 0.11+) deduplicates by message ID.
When to Use This Approach
For high‑traffic, large‑scale distributed systems, the local outbox provides reliability and maintainability and is strongly recommended. Smaller services with low traffic may forego the pattern if the risk and operational cost of occasional inconsistency are acceptable.
The key is to understand the consistency requirements: if strong consistency is not needed, eventual consistency combined with an outbox and idempotent consumers is sufficient.
Takeaways
The “save‑then‑publish” pattern hides a distributed transaction problem; using a local outbox leverages the database’s ACID guarantees to make the business operation and message storage atomic, while a background task ensures eventual delivery. Consumers must be idempotent, or the messaging middleware must provide deduplication, to handle possible duplicate deliveries.
Understanding these trade‑offs lets architects choose the right solution for their specific workload.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
ITPUB
Official ITPUB account sharing technical insights, community news, and exciting events.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
