What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

iTechGuides is reader-supported. When you buy through links on our site, we may earn an affiliate commission. As an Amazon Associate I earn from qualifying purchases. Learn more

To make a Kafka consumer safe to retry, make the destination effect idempotent—not just the producer. For PostgreSQL, a practical pattern is to record a stable event ID under a UNIQUE constraint and apply the business change in the same database transaction. Commit that transaction before committing the Kafka offset. If the consumer crashes in between, the replay hits the same key and the PostgreSQL effect is not applied again. Redis cannot make a Redis write and a PostgreSQL transaction atomic; treat it as an optional optimization unless its behavior under your deployment’s failures is established.

How do I make a Kafka consumer idempotent?

Start by defining the effect you need to protect. Kafka’s at-least-once pattern processes a record and then saves the consumer position. If the destination write succeeds but the offset is not saved before a crash, Kafka can deliver that record again. The consumer has not necessarily lost the record, but its work may happen twice. Apache Kafka’s Kafka 3.2 delivery-semantics documentation describes this process-then-save ordering and the possibility of repeated processing.

For a PostgreSQL effect, put a stable event identity and the business mutation in one transaction. A unique constraint makes PostgreSQL the correctness boundary: only the transaction that newly records that identity applies the mutation. Commit the database transaction, then commit the Kafka offset.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The failure sequence this pattern handles

  1. The consumer reads a Kafka record with event ID evt-123.
  2. In one PostgreSQL transaction, it records that ID and applies the business change.
  3. PostgreSQL commits, but the consumer crashes before Kafka saves the offset.
  4. Kafka delivers the record again. The insert encounters the same unique key, so the consumer skips the business change and can commit the offset.

This protects the PostgreSQL transaction’s effect for that event identity. It does not mean every operation involved in processing the record happened exactly once.

Build the PostgreSQL deduplication boundary

Choose an identity with the right scope

The deduplication key must remain the same across retries and distinguish events that should have distinct effects. A producer-generated event ID can work if it is stable and unique in the intended scope. A source identity such as topic, partition, and offset is another possible key when that is the identity your business logic intends to deduplicate. These are design choices: pick the identity based on what counts as the same event in your application.

PostgreSQL can enforce uniqueness with a unique constraint. Retain the identity record for as long as a replay of the corresponding event must remain harmless. If cleanup removes an identity while an old record can still be replayed, the database no longer has that duplicate guard.

Record the ID and mutate business data in one transaction

The following is an implementation pattern, not tested code. The application checks whether RETURNING produced a row: if it did, it performs the business mutation in the same transaction; if it did not, it skips that mutation. PostgreSQL documents INSERT ... ON CONFLICT as conflict-handling behavior at the database boundary.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
BEGIN;

INSERT INTO processed_events (event_id)
VALUES (:event_id)
ON CONFLICT (event_id) DO NOTHING
RETURNING event_id;

-- If a row was returned, apply the business mutation here.
-- If no row was returned, this event identity was already recorded.

COMMIT;

The placeholder and comments illustrate the application’s control flow; they are not a complete runnable consumer. The business mutation must be conditional on the insert result and part of the same database transaction as the identity record. If the transaction rolls back, both the identity record and mutation roll back together. After the database transaction commits, commit the Kafka offset. If the database transaction fails, do not advance the offset past that record.

Concurrent deliveries of the same identity must also meet the same unique constraint; application-side “check, then insert” logic by itself can race. The constraint and conflict handling are the enforcement point. Keep any other database effects that need the same replay protection in that transaction as well.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

What Redis changes—and what it does not

A Redis marker and a PostgreSQL transaction are separate system operations. Using both does not make them one atomic commit. For example, if the consumer writes a Redis marker and crashes before the PostgreSQL mutation, a retry that trusts the marker and skips processing could leave the business effect unapplied. Reversing the order can leave PostgreSQL committed while Redis has no marker; that is safe only if PostgreSQL still guards the effect on replay.

A conservative design is to make PostgreSQL’s unique key the durable correctness boundary and use Redis only as an optimization that cannot decide whether the business effect is allowed to happen. Before relying on Redis as the authority for deduplication, verify the behavior of your specific deployment for persistence, eviction, replication, failover, key retention, and atomic command execution. Redis command syntax and those guarantees are deployment- and version-specific; do not assume a marker or TTL alone provides the required safety.

  • PostgreSQL authority: a replay reaches the database, where the unique key prevents the protected transaction effect from being repeated.
  • Redis authority: correctness depends on the marker remaining accurate and available for every relevant replay, as well as on coordinating marker changes with the business effect. These systems do not provide that coordination merely by being called from the same consumer.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Kafka idempotence and transactions have a narrower scope

An idempotent Kafka producer addresses certain duplicates caused by producer retries. It does not automatically make a consumer’s write to PostgreSQL or Redis idempotent. Apache Kafka documents producer idempotence and transactional settings in its Kafka 3.9 producer configuration; that mechanism should not be conflated with protecting an external database effect.

Kafka Streams can atomically coordinate input offsets, state changes, and output Kafka topics under its processing guarantees. That Kafka-to-Kafka scope is not a universal exactly-once guarantee for writes to PostgreSQL or Redis. See Apache Kafka’s Kafka 4.1 processing-guarantees documentation for the Streams scope.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Apache Kafka’s design documentation puts the underlying idea plainly: “In many cases messages have a primary key and so the updates are idempotent (receiving the same message twice just overwrites a record with another copy of itself).” That is the useful target for an external effect too: make repeating the same event identity harmless at the system that owns the effect.

Check the design against your failure and retention model

  • Crash after PostgreSQL commit, before offset commit: the record can replay; the unique identity prevents the protected mutation from running again.
  • Crash before PostgreSQL commit: the transaction does not commit its identity and mutation together; do not commit the Kafka offset, so processing can retry.
  • Concurrent duplicate delivery: both attempts must use the same key and rely on the database constraint, not a separate pre-check.
  • Identity cleanup: do not remove a deduplication row while an event with that identity may still be replayed if replay safety depends on that row.
  • Redis marker loss or premature expiry: if Redis is the only deduplication authority, a replay may no longer be recognized. Establish retention and failure behavior before making that a correctness dependency.
  • Multiple external systems: a PostgreSQL transaction protects work performed within that transaction; it does not atomically commit a separate Redis operation or another service call.

The practical meaning of “idempotent consumer” is therefore scoped: identify the effect, enforce a stable identity where that effect is committed, and preserve that identity for the replay window your system must tolerate.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.