Lesson 18 / 25

Idempotent Producers and Transactions

Understand what exactly-once means in Kafka and its boundaries.

Exactly-once inside Kafka

Kafka's transactions let a producer write to several partitions and commit consumer offsets atomically: either all of it becomes visible or none of it. A consume-process-produce application can therefore read from topic A and write to topic B with exactly-once semantics within Kafka: set a transactional.id, wrap the work in begin/commit, and have downstream consumers use isolation.level=read_committed so they never see aborted data. The guarantee covers Kafka reads and writes; if you also update an external database, you still need an idempotent write or a transactional outbox, because Kafka cannot roll back systems it does not control. Frameworks such as Kafka Streams and Flink can provide end-to-end exactly-once for supported sinks.

A transactional producer (illustrative)

Reads from orders, writes to orders-enriched and commits offsets in one transaction. enrich stands for your own function.

p = Producer({"bootstrap.servers": "localhost:9092", "transactional.id": "enricher-1"})
c = Consumer({"bootstrap.servers": "localhost:9092", "group.id": "enricher",
              "enable.auto.commit": False, "isolation.level": "read_committed"})
p.init_transactions()
c.subscribe(["orders"])
while True:
    msg = c.poll(1.0)
    if msg is None or msg.error(): continue
    p.begin_transaction()
    p.produce("orders-enriched", key=msg.key(), value=enrich(msg.value()))
    p.send_offsets_to_transaction(c.position(c.assignment()), c.consumer_group_metadata())
    p.commit_transaction()

Quick check: What does `isolation.level=read_committed` do for a consumer?

  • Hides records from aborted or open transactions
  • Encrypts the records
  • Deletes old records
  • Speeds up the broker
Answer

Hides records from aborted or open transactions — Only committed transactional data is delivered to the consumer.