Skip to content
intermediatePhase 47 · Messaging

Delivery Semantics

Understand at-most-once, at-least-once, and exactly-once delivery.

45m
0 problems
Topic Progress0%

At-Most-Once

At-Most-Once Delivery

At-most-once guarantees a message is delivered zero or one time - never more.

How it Works

At-Most-Once Flow:

1. Producer sends message
2. Message stored in queue
3. Consumer receives message
4. Consumer processes message
5. Consumer acknowledges (BEFORE processing)

If consumer crashes after ack:
- Message lost!
- Never reprocessed
- But never duplicated

Implementation

# Kafka auto-commit (at-most-once)
props.put("enable.auto.commit", "true");
props.put("auto.commit.interval.ms", "5000");

# Messages committed before processing
# Crash after commit = message lost

Trade-offs

Advantage Disadvantage
Fastest delivery May lose messages
Simplest implementation No retry guarantee
Lowest latency Data loss risk

When to Use

  • Log collection (losing some logs OK)
  • Metrics collection (approximate is fine)
  • Non-critical events
  • High throughput, low importance

Example

# At-most-once for metrics
def process_metric(metric):
    # Ack first (message may be lost if crash)
    queue.acknowledge(message_id)
    
    # Then process
    store_metric(metric)

At-Least-Once

At-Least-Once Delivery

At-least-once guarantees a message is delivered one or more times - never zero.

How it Works

At-Least-Once Flow:

1. Producer sends message
2. Consumer receives message
3. Consumer processes message
4. Consumer acknowledges (AFTER processing)

If consumer crashes before ack:
- Message redelivered
- May be processed twice
- But never lost

Implementation

# Kafka manual commit (at-least-once)
props.put("enable.auto.commit", "false");

while (true) {
    ConsumerRecords<String, String> records = consumer.poll(Duration.ofMillis(100));
    for (ConsumerRecord<String, String> record : records) {
        processMessage(record.value());  // Process first
    }
    consumer.commitSync();  // Then commit
}
# Crash before commit = message redelivered

Deduplication Required

class AtLeastOnceConsumer:
    def __init__(self, db):
        self.db = db
    
    def process(self, message):
        # Check if already processed
        if self.db.is_processed(message['id']):
            return  # Skip duplicate
        
        # Process and mark as processed
        with self.db.transaction():
            self.handle(message)
            self.db.mark_processed(message['id'])

Trade-offs

Advantage Disadvantage
No message loss May process duplicates
Reliable delivery Needs idempotency
Common pattern Slightly more complex

When to Use

  • Order processing
  • Payment processing
  • Any critical business logic
  • When duplicates can be handled

Exactly-Once

Exactly-Once Delivery

Exactly-once guarantees a message is delivered exactly one time - no more, no less.

How it Works

Exactly-Once Flow:

1. Producer sends message with unique ID
2. Broker deduplicates by ID
3. Consumer processes message
4. Consumer commits with transaction
5. Consumer marks as processed atomically

Combines:
- Idempotent producer (no duplicates from retries)
- Transactional consumer (atomic processing + commit)

Kafka Implementation

// Idempotent producer
props.put("enable.idempotence", "true");
props.put("acks", "all");
props.put("retries", Integer.MAX_VALUE);

// Transactional consumer
props.put("isolation.level", "read_committed");

// Transaction example
producer.initTransactions();
producer.beginTransaction();
try {
    // Process message
    processMessage(record.value());
    
    // Produce output
    producer.send(new ProducerRecord<>("output-topic", result));
    
    // Commit offset atomically
    producer.sendOffsetsToTransaction(offsets, consumerGroupId);
    
    producer.commitTransaction();
} catch (Exception e) {
    producer.abortTransaction();
}

Components

1. Idempotent Producer:
   - Each message has unique sequence ID
   - Broker deduplicates
   - Prevents producer retries causing duplicates

2. Transactional Consumer:
   - Read committed isolation level
   - Only sees committed messages
   - Atomic processing + offset commit

3. Consumer Offset Transactions:
   - Process message + commit offset atomically
   - Prevents: processed but not committed

Trade-offs

Advantage Disadvantage
No duplicates, no loss Highest complexity
Strongest guarantee Performance overhead
True exactly-once Limited support

When to Use

  • Financial transactions
  • Critical business operations
  • When duplicates are unacceptable
  • When at-least-once + idempotency isn't sufficient

Practice Problems

0/3solved
Design Delivery Semantics System

Design a scalable Delivery Semantics system. Cover high-level architecture, data model, and API design.

Solution
// Complete system design:
// - Functional + Non-functional requirements
// - Capacity estimation
// - Data model (SQL/NoSQL choice)
// - API endpoints
// - Component architecture
// - Scaling strategy
// - Monitoring & reliability
Delivery Semantics Scaling

How would you scale Delivery Semantics to handle 10x the current load? Identify bottlenecks and solutions.

Solution
// Scaling approach:
// 1. Load balancing
// 2. Database sharding/replication
// 3. Cache layer (Redis)
// 4. CDN for static assets
// 5. Async processing (queues)
// 6. Microservices decomposition
Delivery Semantics Failure Modes

Analyze potential failure modes for Delivery Semantics and design mitigation strategies.

Solution
// Failure mitigation:
// 1. Redundancy (multi-AZ)
// 2. Circuit breakers
// 3. Retry with backoff
// 4. Dead letter queues
// 5. Health checks
// 6. Graceful degradation

Quiz

1. What does at-most-once guarantee?

Question 1 options

2. Why does at-least-once need idempotency?

Question 2 options

3. What makes exactly-once different from at-least-once?

Question 3 options

4. Which delivery semantic is simplest?

Question 4 options

5. When should you use exactly-once delivery?

Question 5 options

Flashcards

Question

At-most-once guarantee?

Answer

Message delivered 0 or 1 time - may lose messages but never duplicates. Ack before processing.

Question

At-least-once guarantee?

Answer

Message delivered 1+ times - never lost but may duplicate. Ack after processing. Needs idempotency.

Question

Exactly-once guarantee?

Answer

Message delivered exactly once. Uses idempotent producer + transactional consumer for atomic processing.

Question

Why idempotent consumer needed?

Answer

At-least-once may redeliver messages; idempotent consumer handles duplicates safely

Question

When use each delivery semantic?

Answer

At-most-once: logs/metrics. At-least-once: order processing. Exactly-once: financial transactions.

Revision Notes

Key Takeaways

  • 1.At-most-once: simple, may lose messages
  • 2.At-least-once: reliable, needs idempotency for duplicates
  • 3.Exactly-once: strongest guarantee, highest complexity
  • 4.Choose based on business requirements
  • 5.At-least-once + idempotency is most common

Interview Tips

  • Know the three semantics and their trade-offs
  • Explain why at-least-once needs idempotency
  • Discuss exactly-once implementation with Kafka transactions
  • Give examples of when to use each semantic

Cheat Sheet

Cheat Sheet: Delivery Semantics

At-Most-Once

  • 0 or 1 delivery
  • Ack before processing
  • May lose messages
  • Use: Logs, metrics

At-Least-Once

  • 1+ delivery
  • Ack after processing
  • May duplicate
  • Needs idempotency
  • Use: Order processing

Exactly-Once

  • Exactly 1 delivery
  • Idempotent producer
  • Transactional consumer
  • Atomic processing + commit
  • Use: Financial

Trade-offs

Simple → Complex
At-most → At-least → Exactly