CodePark/ questions / Retries, poison messages & DLQs
START PRACTICINGPRACTICE
Backend question · Message queues & streaming › Retries, poison messages & DLQs

Kafka has no per-message ack or built-in DLQ for plain consumers. How do you handle a record that keeps failing without blocking its partition?

Move the failing record to a separate retry topic, commit its offset, and let the partition continue. If the consumer keeps retrying in place, it never commits past the bad record. Everything behind it in that partition then waits. A few quick retries in place are fine for short transient errors. Longer waits are not.

The common pattern is retry topics:

  • On failure, the consumer publishes the record to a delay topic such as orders.retry.1m. It adds headers with the attempt count, the error and the original topic.
  • The consumer commits the original offset, so the partition moves on.
  • A retry consumer reads that topic. It waits until the record's delay has passed. It pauses the partition instead of sleeping in the poll loop.
  • A second tier, such as orders.retry.10m, catches records that fail again.
  • After the last tier, the record goes to a dead-letter topic, orders.dlt.

The trade-off is ordering. A retried record is processed after later records with the same key. If that matters, you can also hold back (park) later records for that key. Or you can block the partition on purpose.

  • Retrying in place stalls the whole partition.
  • Publish failures to delay tiers like retry.1m and retry.10m, then to a DLT (dead-letter topic).
  • Commit the original offset so the partition continues.
  • Carry the attempt count and error in headers, and pause the partition instead of sleeping.
  • Retried records lose their order relative to later records with the same key.