MESSAGING & EVENT-DRIVEN ARCHITECTURE / SYSTEM CONCEPT BRIEF

Delivery guarantees

Delivery guarantees describe how many times a message may be processed.

IntermediatePhase 06 / Topic 17 of 18RequirementsTrade-offsFailure modes
01

Overview

Delivery guarantees describe how many times a message may be processed. At-most-once: messages may be lost but never duplicated (ack before processing). At-least-once: messages are never lost but may be duplicated (ack after processing). Exactly-once: each message affects the result exactly one time.

True exactly-once delivery over a network is impossible in general, because a lost acknowledgment makes the sender retry. What systems actually provide is exactly-once processing: at-least-once delivery combined with idempotent or transactional processing, so duplicates have no extra effect. Kafka's transactions offer this within Kafka (read-process-write).

Sending an important letter

At-most-once is dropping it in a mailbox and hoping. At-least-once is sending it again until you get a receipt, so the recipient might get two copies. Exactly-once is sending until you get a receipt, with the recipient throwing away duplicates by checking a reference number.

02

When to use it

  • Designing any messaging pipeline.
  • Payments, billing, and inventory where duplicates matter.
  • Metrics and logs where occasional loss may be acceptable.
  • Interview questions about reliability semantics.
03

Where it shows up in interviews

Choosing semantics

Recognize it when: what happens if a message is lost or duplicated?

  • Design a payment event pipeline
  • Design a metrics collection system
Exactly-once processing

Recognize it when: count or charge exactly once.

  • Design ad click billing
  • Design a ledger from events
04

Where it is used in real software

Kafka EOS

Idempotent producers plus transactions make consume-transform-produce pipelines exactly-once within Kafka.

SQS standard vs FIFO

Standard is at-least-once; FIFO provides exactly-once processing within a deduplication window.

Flink checkpoints

Consistent snapshots of state and offsets give exactly-once state updates; sinks need transactions or idempotence.

05

Key terms

At-most-once
Zero or one time; possible loss.
At-least-once
One or more times; possible duplicates.
Exactly-once processing
Effect applied once, via dedupe or transactions.
Acknowledgment timing
Before processing = at-most-once; after = at-least-once.
Deduplication
Recognizing repeated messages by ID.
06

How it works, step by step

  1. 1
    Pick the requirement

    Can you lose messages? Can you tolerate duplicates?

  2. 2
    Producer side

    Retries with idempotent producers or dedupe IDs.

  3. 3
    Broker side

    Replicate and acknowledge durably (acks=all).

  4. 4
    Consumer side

    Process, then commit or ack.

  5. 5
    Make effects idempotent

    Dedupe table or transactional writes with offsets.

07

Where ack timing leads

Consumer crashes at different points

Step 1 / 3
StrategyCrash after ack, before processingCrash after processing, before ackGuarantee
Ack then processMessage lostN/AAt-most-once
Process then ackN/AMessage processed twiceAt-least-once
Process + record ID atomically, then ackN/ADuplicate detected and skippedExactly-once effect

NOWStrategy: Ack then process | Crash after ack, before processing: Message lost | Crash after processing, before ack: N/A | Guarantee: At-most-once

Exactly-once is at-least-once delivery plus idempotent processing.

08

Implementation

// Exactly-once effect: store the processed message ID in the same transaction as the side effectexport async function handlePaymentEvent(msg: { id: string; accountId: string; amountCents: number }) {  await db.transaction(async (tx) => {    const inserted = await tx.query(      "INSERT INTO processed_messages (message_id) VALUES ($1) ON CONFLICT DO NOTHING RETURNING message_id",      [msg.id],    );    if (inserted.rowCount === 0) return; // duplicate delivery: already applied     await tx.query("INSERT INTO ledger (account_id, amount_cents, source_message) VALUES ($1, $2, $3)",      [msg.accountId, msg.amountCents, msg.id]);  });  // ack/commit offset only after the transaction commits (at-least-once delivery)}
09

Complexity and performance

At-most-once costLowest

No retries or dedupe.

Exactly-once cost+ dedupe write or transaction

Per message.

10

Trade-offs

Reliability vs overhead

Stronger guarantees add storage, latency, and complexity; choose per data flow.

Broker EOS vs end-to-end

Kafka EOS covers Kafka-to-Kafka flows; external side effects (email, payments) still need idempotency.

11

Variants and related techniques

Transactional outbox

Producer-side guarantee that DB changes and events are published together.

Dedupe windows

Remember IDs for a bounded time (SQS FIFO 5 minutes).

12

Common mistakes

  • Believing a broker's 'exactly-once' covers external side effects.

    Fix: Emails and API calls still need idempotency keys.

  • Auto-commit offsets.

    Fix: Offsets may be committed before processing, losing messages on crash.

13

Interview questions

Is exactly-once delivery possible?

Not strictly over an unreliable network, because the sender cannot distinguish a lost message from a lost ack. Systems achieve exactly-once processing by combining at-least-once delivery with idempotent or transactional consumers.

Which guarantee would you choose for metrics vs payments?

Metrics can often use at-most-once or at-least-once with approximate dedupe; payments need at-least-once delivery with strict idempotent processing so each payment is applied exactly once.

14

Practice problems

ProblemDifficultyWhat it trains
Classify 5 pipelines by delivery guaranteeEasyRequirements.
Implement exactly-once ledger updates from a queueMediumDedupe in transaction.