I think about update propagation whenever one fact appears in many places: database row, cache, search index, report, and notification view. I recommend designing how copies catch up before users find stale truth.
Copies need a delivery path and a lag budget
When I talk about "Copies need a delivery path and a lag budget", I am really asking what Update Propagation does when a message is late, duplicated, or missing.
The design should name the source of truth, the propagation mechanism, and the expected delay. Without that, stale reads look like random bugs.
Cache update example
I use "Cache update example" to keep Update Propagation grounded in a real system, because abstract patterns are too easy to agree with and too hard to operate.
A price manager changes a product price. The catalog database updates first. Cache, search, and recommendation views receive events and refresh their copies.
Versioned update code
When I show "Versioned update code", I want the code in Update Propagation to reveal the production decision, not just the syntax.
The outbox keeps the data write and the propagation signal together:
database.transaction(() -> {
catalog.save(newPrice);
outbox.add(new ProductPriceChanged(productId, newPrice));
});
The database update and outbox event are saved in the same transaction. That prevents a price change from being committed without a matching propagation event.
Sequence diagram: one update, several copies
The update is not complete everywhere at once. The propagation path makes the delay visible and manageable.
The freshness rule
- Name the source of truth for each field.
- Monitor propagation delay and failed consumers.
- Design cache invalidation as part of the write path.