Exactly-Once Patterns

Exactly-Once Stream Processing Patterns

The core pattern is consume-transform-produce: read a batch, write the results, and commit the input offsets inside the same transaction, so that results and progress move together. After a crash the job resumes from the last committed offsets, and the results of the unfinished batch are aborted.

Consume-transform-produce: results and input offsets commit in one transaction
Consume-transform-produce: results and input offsets commit in one transaction
Exactly-once options by pipeline edge
Situation Pattern
Kafka 129 to Kafka, your own code Transactions with send_offsets_to_transaction()
Kafka Streams 129 processing.guarantee=exactly_once_v2 (Kafka Streams)
Flink 129 to Kafka Two-phase commit sink (ksqlDB and Apache Flink)
Kafka to a database Idempotent upsert keyed by event_id, or offsets in the same database transaction
Database to Kafka Transactional outbox table plus CDC (Orchestration and Pipelines)

Kafka's transactions stop at Kafka's edge: an e-mail sent or a card charged inside the loop happens again when the batch is retried. Make such side effects idempotent, or move them to a consumer that records what it has done.