The Acknowledgment Gap: How Event-Driven Systems Silently Lose Messages
Why do event-driven systems silently drop messages between acceptance and completion? A deep dive into the acknowledgment gap and its fixes.
This piece examines a subtle failure mode in event-driven systems: the gap between a component reporting that work was "accepted" versus "completed." A consumer dispatches a job to a downstream control plane, receives a 202 or 204 response, and treats that as success - but the job can still be rejected moments later, entirely outside the consumer's view. By the time that happens, the consumer has already committed its offset, and the broker will never redeliver the message.
The root cause is architectural: offset commits in systems like Kafka are a promise about the past - "everything up to here has been handled." When that promise is based on an ambiguous acknowledgment rather than actual task completion, the system manufactures data loss without throwing a single exception. The analysis also shows why common instincts - checking status codes, adding retries, enforcing idempotency, or reaching for exactly-once semantics - fail to close this gap, since none of them address the mismatch between acceptance and execution.
For engineers building async pipelines, the takeaway is that any handoff across an asynchronous boundary needs its acknowledgment moved to the point of actual completion, not mere acceptance - otherwise silent, unrecoverable loss becomes possible even in a system that looks perfectly healthy.