← All decisions jacob@stephens.page
Decision Record

Binlog-tailing daemons over database triggers for denormalization

ADR 0006 · Accepted ยท in production · ~333 words

Context

A read-heavy reservations system keeps a lot of derived data in sync with its source rows - rolled-up totals, denormalized copies of a value onto the rows that query it, search-friendly projections. The in-database default for keeping derived data current is a TRIGGER that fires on every write. But triggers run inside each writing transaction and are invisible to the application. They're awkward to test, version, and deploy - they're schema DDL, not code - and a slow or buggy one adds latency to (or wedges) the hot write path.

Decision

Move the sync logic out of the database and into a set of small daemons that tail the database's replication log (binlog) under a process manager. They react to committed row changes asynchronously and write the derived data back. The logic lives in application code, in version control, deployed like everything else (see ADR 0004).

Consequences

When I'd revisit

For an invariant that must hold within the writing transaction - a hard correctness constraint, not a derived convenience - a trigger or a database constraint is the right tool. Anything that can't tolerate lag belongs in the database; everything that can is cheaper and safer to own as code.

One of a set of architecture decision records. Source markdown lives in the infrastructure-patterns repo, which is the canonical copy.