MindForge
MindForge
DashboardHelp & Support
Dashboard
MindForge

Interview Preparation Bootcamp

Course progress

0%
0 of 177 modules complete
Start Here0/1
  • How to Use This Course
Data Structures & Algorithms0/27
  • Arrays and Hashing
  • Two Pointers
  • Sliding Window
  • Sliding Window: Harder Problems
  • Binary Search
  • Stacks
  • Practice Test: Arrays, Pointers, Windows, Search and Stacks
  • Trees: Traversals and Core Patterns
  • Binary Search Trees and Rebuilding a Tree
  • Tries (Prefix Trees)
  • Heaps and Priority Queues
  • Graphs: BFS and DFS
  • Topological Sort and Cycle Detection
  • Union-Find (Disjoint Set Union)
  • Practice Test: Trees, Heaps and Graphs
  • Dynamic Programming Basics
  • Dynamic Programming: Two Dimensions
  • Dynamic Programming: Hard String Matching
  • Backtracking
  • Backtracking: Constraint Satisfaction
  • Greedy Algorithms
  • Interval Problems
  • Bit Manipulation
  • Math and Geometry
  • String Manipulation
  • Pattern Recall and Mock Coding Rounds
  • Practice Test: DP, Backtracking, Greedy and More

System Design

Foundations0/16
  • The System Design Interview Framework
  • Back-of-the-Envelope Estimation
  • Networking and Protocols for Design
  • API Design and Idempotency
  • Load Balancing, Proxies, and Scaling Out
  • Caching and CDNs
  • Choosing a Database: Storage, Indexes and Transactions
  • Replication, Partitioning, and Sharding
  • CAP, PACELC, and Levels of Consistency
  • Messaging, Queues, and Event-Driven Architecture
  • Distributed Transactions and Data Integrity
  • Coordination, Consensus, and Distributed Locks
  • Reliability, Resilience, and Rate Limiting
  • Observability, Security, and Cost
  • System Design Cheat Sheet
  • Practice Test: System Design Foundations
Case Studies0/23
  • Design a URL Shortener
  • Design a Rate Limiter
  • Design a Notification Service
  • Design a Job Queue System
  • Design a Chat App (WhatsApp)
  • Design an Analytics Pipeline
  • Design a Multi-tenant SaaS Architecture
  • Design a Social Media Feed (Twitter/X)
  • Design a Search Autocomplete System
  • Design a File Storage Service (Dropbox)
  • Design Google Docs
  • Design a Code Review System
  • Design Netflix
  • Design YouTube
  • Design Spotify
  • Design Uber/Lyft
  • Design Airbnb
  • Design Ticketmaster (Eventbrite)
  • Design an E-commerce Cart, Checkout, and Catalog
  • Design a Payment System
  • Design a Logging and Monitoring System
  • Mock Design Rounds
  • Practice Test: System Design Case Studies
Low-Level Design0/19
  • The LLD Interview Framework and UML
  • OOP Foundations for Design
  • SOLID Principles
  • Creational Patterns
  • Structural Patterns
  • Behavioral Patterns I — Strategy, Observer, Command, State, Template Method
  • Behavioral Patterns II and Anti-Patterns
  • Concurrency in Low-Level Design
  • Design a Parking Lot
  • Design an Elevator System
  • Design a Movie Ticket Booking System
  • Design an Expense-Sharing App (Splitwise)
  • Design a Vending Machine and an ATM
  • Design a Rate Limiter and a Logging Framework
  • Design a Notification Service and an In-Memory Cache
  • Design Games — Tic-Tac-Toe, Snake and Ladder, Chess
  • Database Design for LLD
  • LLD Cheat Sheet and Recall Drill
  • Practice Test: Low-Level Design

Backend

Python0/5
  • How Python Runs Your Code
  • Functions Deep Dive: Closures, Generators, Context Managers, Scope
  • Classes Deep Dive: Method Types, MRO, Metaclasses
  • Standard Library and Serialization
  • Practice Test: Python
Django0/6
  • Django Request Lifecycle
  • Lab: Django Middleware — Request ID & Response Time
  • Django ORM and Querysets
  • Django's Cache Framework
  • Practice Test: Django
  • Django in Production: Debugging Labs
FastAPI0/5
  • FastAPI, ASGI, and Async
  • FastAPI Dependency Injection
  • FastAPI Background Tasks
  • Lab: FastAPI Async — Concurrent Aggregation
  • Practice Test: FastAPI
Databases (PostgreSQL)0/6
  • Indexing
  • Query Optimization
  • Transactions and Isolation
  • Migrations and Schema Changes
  • Hierarchical Data and Safe Concurrent Updates
  • Practice Test: Databases
Caching, Queues & Distributed Systems0/8
  • Redis Caching
  • Redis Advanced Patterns
  • Celery and Background Workers
  • Kafka and Message Queues
  • Async Pipelines
  • Distributed Systems Basics
  • Distributed Locks
  • Practice Test: Caching, Queues and Distributed Systems
APIs, Security & Deployment0/9
  • REST API Design
  • API Versioning and Error Handling
  • API Security and Authentication
  • WebSockets and Real-Time Systems
  • Docker and Containers
  • File Storage with S3
  • Testing Strategies
  • Mock Backend Round
  • Practice Test: APIs, Security and Deployment
Frontend0/38
  • HTML Document Structure and Semantics
  • CSS Box Model, Flexbox and Grid
  • CSS Architecture and Theming
  • CSS and Rendering Performance
  • Variables, Scope, Hoisting, and Truthiness
  • Functions, this, and Binding
  • Objects and Prototypal Inheritance
  • JavaScript Utility Patterns: Cloning, Caching, and Memory
  • Promises From Scratch
  • The Event Loop and Browser Rendering Pipeline
  • The DOM: Nodes, Events, and Traversal
  • Practice Test: HTML, CSS and JavaScript
  • React Rendering Fundamentals
  • React Hooks Internals
  • React Performance
  • Lab: React — Stateful Counter Component
  • State Management
  • State Machines in React
  • React Custom Hooks and Composition Patterns
  • TypeScript for React
  • React Testing
  • Practice Test: React
  • HTTP and Caching
  • Network Performance and Web Vitals
  • Code Splitting and Bundles
  • Virtualization
  • GraphQL and Data Fetching
  • Web Security
  • WebSockets and Real-time
  • SSR and Next.js
  • Micro-frontends
  • Build Tools and Bundling
  • Accessibility
  • Error Handling
  • Internationalization
  • Animation
  • Rapid Recall and Mock Frontend Rounds
  • Practice Test: Performance, Architecture and Production
Behavioral & Interview Day0/14
  • Resume and Project Walkthroughs
  • The STAR Method and Refining Your Stories
  • Conflict and Difficult Coworkers
  • Failures, Incidents, and Obstacles
  • Leadership, Mentorship, and Ownership
  • Teamwork, Communication, and Feedback
  • Growth and Handling Ambiguity
  • Career Goals, Why This Company, and Negotiation
  • Situational Questions
  • Company Research
  • Mock Behavioral Rounds
  • Interview Day
  • After the Interview
  • Practice Test: Behavioral and Interview Day
Messaging, Queues, and Event-Driven Architecture
Course contents

Interview Preparation Bootcamp

Course progress

0%
0 of 177 modules complete
Start Here0/1
  • How to Use This Course
Data Structures & Algorithms0/27
  • Arrays and Hashing
  • Two Pointers
  • Sliding Window
  • Sliding Window: Harder Problems
  • Binary Search
  • Stacks
  • Practice Test: Arrays, Pointers, Windows, Search and Stacks
  • Trees: Traversals and Core Patterns
  • Binary Search Trees and Rebuilding a Tree
  • Tries (Prefix Trees)
  • Heaps and Priority Queues
  • Graphs: BFS and DFS
  • Topological Sort and Cycle Detection
  • Union-Find (Disjoint Set Union)
  • Practice Test: Trees, Heaps and Graphs
  • Dynamic Programming Basics
  • Dynamic Programming: Two Dimensions
  • Dynamic Programming: Hard String Matching
  • Backtracking
  • Backtracking: Constraint Satisfaction
  • Greedy Algorithms
  • Interval Problems
  • Bit Manipulation
  • Math and Geometry
  • String Manipulation
  • Pattern Recall and Mock Coding Rounds
  • Practice Test: DP, Backtracking, Greedy and More

System Design

Foundations0/16
  • The System Design Interview Framework
  • Back-of-the-Envelope Estimation
  • Networking and Protocols for Design
  • API Design and Idempotency
  • Load Balancing, Proxies, and Scaling Out
  • Caching and CDNs
  • Choosing a Database: Storage, Indexes and Transactions
  • Replication, Partitioning, and Sharding
  • CAP, PACELC, and Levels of Consistency
  • Messaging, Queues, and Event-Driven Architecture
  • Distributed Transactions and Data Integrity
  • Coordination, Consensus, and Distributed Locks
  • Reliability, Resilience, and Rate Limiting
  • Observability, Security, and Cost
  • System Design Cheat Sheet
  • Practice Test: System Design Foundations
Case Studies0/23
  • Design a URL Shortener
  • Design a Rate Limiter
  • Design a Notification Service
  • Design a Job Queue System
  • Design a Chat App (WhatsApp)
  • Design an Analytics Pipeline
  • Design a Multi-tenant SaaS Architecture
  • Design a Social Media Feed (Twitter/X)
  • Design a Search Autocomplete System
  • Design a File Storage Service (Dropbox)
  • Design Google Docs
  • Design a Code Review System
  • Design Netflix
  • Design YouTube
  • Design Spotify
  • Design Uber/Lyft
  • Design Airbnb
  • Design Ticketmaster (Eventbrite)
  • Design an E-commerce Cart, Checkout, and Catalog
  • Design a Payment System
  • Design a Logging and Monitoring System
  • Mock Design Rounds
  • Practice Test: System Design Case Studies
Low-Level Design0/19
  • The LLD Interview Framework and UML
  • OOP Foundations for Design
  • SOLID Principles
  • Creational Patterns
  • Structural Patterns
  • Behavioral Patterns I — Strategy, Observer, Command, State, Template Method
  • Behavioral Patterns II and Anti-Patterns
  • Concurrency in Low-Level Design
  • Design a Parking Lot
  • Design an Elevator System
  • Design a Movie Ticket Booking System
  • Design an Expense-Sharing App (Splitwise)
  • Design a Vending Machine and an ATM
  • Design a Rate Limiter and a Logging Framework
  • Design a Notification Service and an In-Memory Cache
  • Design Games — Tic-Tac-Toe, Snake and Ladder, Chess
  • Database Design for LLD
  • LLD Cheat Sheet and Recall Drill
  • Practice Test: Low-Level Design

Backend

Python0/5
  • How Python Runs Your Code
  • Functions Deep Dive: Closures, Generators, Context Managers, Scope
  • Classes Deep Dive: Method Types, MRO, Metaclasses
  • Standard Library and Serialization
  • Practice Test: Python
Django0/6
  • Django Request Lifecycle
  • Lab: Django Middleware — Request ID & Response Time
  • Django ORM and Querysets
  • Django's Cache Framework
  • Practice Test: Django
  • Django in Production: Debugging Labs
FastAPI0/5
  • FastAPI, ASGI, and Async
  • FastAPI Dependency Injection
  • FastAPI Background Tasks
  • Lab: FastAPI Async — Concurrent Aggregation
  • Practice Test: FastAPI
Databases (PostgreSQL)0/6
  • Indexing
  • Query Optimization
  • Transactions and Isolation
  • Migrations and Schema Changes
  • Hierarchical Data and Safe Concurrent Updates
  • Practice Test: Databases
Caching, Queues & Distributed Systems0/8
  • Redis Caching
  • Redis Advanced Patterns
  • Celery and Background Workers
  • Kafka and Message Queues
  • Async Pipelines
  • Distributed Systems Basics
  • Distributed Locks
  • Practice Test: Caching, Queues and Distributed Systems
APIs, Security & Deployment0/9
  • REST API Design
  • API Versioning and Error Handling
  • API Security and Authentication
  • WebSockets and Real-Time Systems
  • Docker and Containers
  • File Storage with S3
  • Testing Strategies
  • Mock Backend Round
  • Practice Test: APIs, Security and Deployment
Frontend0/38
  • HTML Document Structure and Semantics
  • CSS Box Model, Flexbox and Grid
  • CSS Architecture and Theming
  • CSS and Rendering Performance
  • Variables, Scope, Hoisting, and Truthiness
  • Functions, this, and Binding
  • Objects and Prototypal Inheritance
  • JavaScript Utility Patterns: Cloning, Caching, and Memory
  • Promises From Scratch
  • The Event Loop and Browser Rendering Pipeline
  • The DOM: Nodes, Events, and Traversal
  • Practice Test: HTML, CSS and JavaScript
  • React Rendering Fundamentals
  • React Hooks Internals
  • React Performance
  • Lab: React — Stateful Counter Component
  • State Management
  • State Machines in React
  • React Custom Hooks and Composition Patterns
  • TypeScript for React
  • React Testing
  • Practice Test: React
  • HTTP and Caching
  • Network Performance and Web Vitals
  • Code Splitting and Bundles
  • Virtualization
  • GraphQL and Data Fetching
  • Web Security
  • WebSockets and Real-time
  • SSR and Next.js
  • Micro-frontends
  • Build Tools and Bundling
  • Accessibility
  • Error Handling
  • Internationalization
  • Animation
  • Rapid Recall and Mock Frontend Rounds
  • Practice Test: Performance, Architecture and Production
Behavioral & Interview Day0/14
  • Resume and Project Walkthroughs
  • The STAR Method and Refining Your Stories
  • Conflict and Difficult Coworkers
  • Failures, Incidents, and Obstacles
  • Leadership, Mentorship, and Ownership
  • Teamwork, Communication, and Feedback
  • Growth and Handling Ambiguity
  • Career Goals, Why This Company, and Negotiation
  • Situational Questions
  • Company Research
  • Mock Behavioral Rounds
  • Interview Day
  • After the Interview
  • Practice Test: Behavioral and Interview Day
Browsing without an account — progress is saved in this browser only.Sign in to save it

Messaging, Queues, and Event-Driven Architecture

Reading50 min

The moment you draw a queue on the whiteboard, an interviewer has four follow-up questions ready: what happens if whoever's processing the message crashes halfway through, what happens if the same message gets delivered twice, is the order of messages preserved, and what happens if messages arrive faster than they can be processed. Walk in with all four answers ready, and this becomes one of the strongest parts of your whole design.

Why a queue, and where the line goes

A queue does four genuinely different jobs, and being able to name which one you actually need is what separates "I'd just add a message broker like Kafka" from a design that's actually been thought through.

Job What it buys you Example
Decoupling The producer doesn't need to know about, or wait on, its consumers An order service announces "order placed," and separately, email, analytics, and inventory each pick that up
Buffering / smoothing out spikes Absorbs a sudden rush of traffic so the slower side isn't overwhelmed 50,000 signups during a flash sale drain into a pool of workers at whatever pace they can handle
Moving slow work out of the way Keeps slow work off the path a user is waiting on Converting video, generating a PDF, sending bulk email
Retrying safely, without losing anything A failed piece of work isn't simply lost Retrying a failed payment notification with increasing delays

Here's the line to draw in every design you build: anything the user's response doesn't depend on goes behind a queue. Creating an order has to save that order and reply right away. Sending the confirmation email, updating a recommendation model, indexing for search, and telling the warehouse can all happen a moment later, in the background.

There are real costs here, and you should mention them yourself before you're asked.

  • The delay becomes visible to users. "Your order is placed" shows up instantly, but the confirmation email might arrive 30 seconds later, and an analytics dashboard might lag behind by more.
  • Debugging gets harder. A failure now shows up in a background worker's log, not in the original request's trace, unless you deliberately carry a shared trace ID through both.
  • It's another whole system to run: the message broker itself, how its partitions are managed, watching for messages piling up, and handling messages that keep failing.

Remember: if the user's response doesn't depend on it, put it behind a queue. Everything else stays in the request path.

Sign in to try this knowledge check.

Queue vs log: the distinction that matters

Picture a to-do list, where you cross an item off and it's gone for good, compared with a diary, where every entry stays on the page forever and you can flip back and reread any day you like. A to-do list works like a message queue. A diary works like what's called a distributed log. Picking the wrong shape for the job is a common and expensive mistake.

A message queue, like RabbitMQ, SQS, or ActiveMQ, delivers each message to exactly one consumer, who processes it and confirms it, and the broker then deletes it. The broker keeps track of each individual message's state.

A distributed log, like Kafka, Kinesis, Redpanda, or Pulsar, appends every message to an ordered, kept log, split into partitions. Consumers each track their own position, called an offset, and read at their own pace; a message is never deleted just because someone read it. Many separate groups of consumers can all read the very same stream, each independently.

Queue (RabbitMQ/SQS) Log (Kafka)
What happens after it's read Deleted Kept for a set time or size
How many consumers per message One, per queue Many independent groups
Can you replay old history No Yes, by resetting your offset
Ordering Only within one queue, and lost once several consumers share it Strict, within each partition
Routing options Rich: exchanges, topics, headers, priorities Simple: a topic, split into partitions
Confirming or retrying one message Built in, per message Per offset; one stuck message blocks its whole partition
How much it can handle High Very high, thanks to sequential disk writes and batching
Typical use Task queues, work that's like a remote call, priority-based routing Streams of events, database change feeds, analytics, replaying full history

The decision rule is simple: do you need to replay history, or have several independent consumers each read the same events? Use a log. Do you need per-message routing, priorities, or delayed retries? Use a queue.

In Kafka, partitions are the unit both of how much work can happen in parallel and of ordering itself: messages sharing the same key always go to the same partition and stay strictly ordered there, and each partition is only ever read by one consumer within a given group. So the number of partitions is the most work you can do in parallel, and the key you choose is what keeps things belonging to the same entity in order; keying by user_id, for instance, keeps one user's own events ordered, even though the topic as a whole is not.

Remember: a queue deletes a message once it's read. A log keeps every message, so many independent readers can each replay it at their own pace. Pick a log whenever you need to replay history.

Sign in to try this knowledge check.

Delivery semantics and idempotent consumers

There are three possible promises a message system can make, and only two of them are actually achievable.

Promise How it's done What can go wrong
At-most-once Confirm the message before doing the work The message is lost if the worker crashes mid-way through
At-least-once Confirm the message after doing the work Duplicates appear if the confirmation itself gets lost after the work was already done
Exactly-once Not actually achievable end to end, across separate systems —

At-least-once is both the default and the right choice, because losing work outright is usually worse than accidentally doing it twice. That means handling duplicates isn't an edge case; it's a real design requirement.

When Kafka advertises "exactly-once," it means exactly-once inside Kafka itself, through transactional writes across its own topics with a producer that avoids sending the same thing twice. The moment your consumer actually charges a card or sends an email, that's an effect happening out in the real world, one that Kafka's own transaction has no power to undo. The honest way to describe this, and the answer interviewers actually want to hear, is: "at-least-once delivery plus idempotent processing gives you effectively-once behaviour."

Here's how you actually make a consumer idempotent, meaning safe to run more than once:

Python
def handle(msg):
    # 1. Natural idempotency — the operation is safe to repeat as-is.
    #    "SET status = 'shipped'" is idempotent; "counter += 1" is not.

    # 2. Deduplication table — the general mechanism.
    #    The UNIQUE constraint is what makes it race-safe, not the SELECT.
    try:
        db.execute(
            "INSERT INTO processed_messages (message_id, processed_at) VALUES (%s, now())",
            msg.id,
        )
    except UniqueViolation:
        return  # already handled; ack and move on

    do_the_work(msg)

    # 3. Better still: do the work and record the message id in ONE transaction,
    #    so a crash between them cannot leave the dedupe row without the effect.

Two more patterns worth knowing by name.

Conditional writes: a statement like UPDATE orders SET status='shipped' WHERE id=? AND status='paid' has the same effect no matter how many times you run it, because it only applies once the row is actually in the expected starting state.

Version or sequence checks: ignore any incoming event whose version number isn't exactly one greater than the one you already have stored.

Remember: duplicates are guaranteed in a distributed system, so design for them. "At-least-once delivery plus an idempotent consumer" is the honest, achievable promise, not "exactly-once."

Sign in to try this knowledge check.

Ordering, retries, dead letters, and backpressure

Ordering across an entire topic is expensive, and you almost never actually need it. Ordering per entity usually is what you need instead. Partitioning by the entity's own key, like user_id, account_id, or conversation_id, gives you strict order exactly where it matters, while still letting different entities be processed in parallel. If you genuinely need every single message globally ordered, you're stuck with one partition and one consumer; say that cost out loud when you propose it.

Ordering quietly breaks in three common situations: several consumers sharing one queue, a retried message getting pushed behind newer ones that arrived after it, and changing the number of partitions, which changes which partition a given key lands in.

Retries should use exponential backoff with a bit of randomness added, called jitter. If every failed client retries after exactly the same fixed delay, they all end up retrying together in a wave, called a thundering herd.

delay = min(base * 2**attempt, max_delay) * random_between(0.5, 1.5)

Always put a cap on the number of attempts. Also tell apart failures that are worth retrying, like a timeout or a temporary overload, from ones that are permanent, like a validation error; retrying a message that's simply malformed forever is pure waste, and it blocks everything behind it in the same partition.

A dead letter queue is where a message goes after failing too many times. After N attempts, move it there along with its error and how many times it was tried. Nothing is lost, the main flow keeps moving, and a person, or a separate fixed-up consumer, can retry it later. Always alert on how many messages are sitting in the dead letter queue; a dead letter queue nobody is watching is a data-loss incident that nobody has noticed yet.

Backpressure is what happens when producers create messages faster than consumers can process them. The queue keeps growing, memory and disk fill up, and response times climb until something breaks. Your options are:

  1. Scale up the number of consumers, automatically, based on how deep the queue is or how far behind consumers are. In Kafka, this only helps up to the number of partitions you have.
  2. Put a hard limit on the queue's size, and reject or pause producers once it's full. Failing immediately and clearly is better than slowly grinding to a halt.
  3. Shed load on purpose: drop lower-priority messages, or only process a sample of them.
  4. Rate limit the producers themselves.

The single most important metric here is consumer lag, meaning how far behind consumers are from the latest message. In Kafka this is the gap between offsets; in SQS it's how old the oldest unprocessed message is. Watch the trend in that lag over time, not just its current value: lag that keeps steadily growing means you simply don't have enough consumers, and waiting longer will never fix that on its own.

Remember: one bad message can block a whole partition if you keep retrying it forever. Move it to a dead-letter queue after N attempts, and alert on that queue's depth.

Sign in to try this knowledge check.

Event-driven patterns: pub/sub, outbox, event sourcing, CQRS

Point-to-point versus publish/subscribe. Point-to-point means one producer, one consumer, one queue, like a personal to-do list. Publish/subscribe, often shortened to pub/sub, means one event has many independent subscribers, like a public announcement everyone can hear. Prefer publishing facts, like "order placed," over issuing commands, like "send the email." Publishing a fact lets you add a fourth listener later without ever touching the original producer, which is the entire point of decoupling systems in the first place.

The dual-write problem, and the outbox pattern that fixes it, is the single most valuable idea in this whole topic. Picture writing a cheque, and then, on a separate trip, walking to the post office to mail someone a receipt for it. If you get hit by a bus in between those two trips, the cheque now exists, but nobody was ever told about it. Saving something to a database and then separately publishing an event to a message broker has exactly this same problem: it isn't one single atomic action. A crash in between the two can leave the order saved but never announced, or announced without ever actually being saved.

Wrong:   BEGIN; INSERT order; COMMIT;   kafka.publish(event)   ← crash here = lost event

Right:   BEGIN;
           INSERT INTO orders   (...);
           INSERT INTO outbox   (id, topic, payload, created_at);   -- same transaction
         COMMIT;
         -- a separate relay (CDC on the WAL, or a poller) reads outbox and publishes,
         -- marking rows sent. At-least-once by construction; consumers dedupe.

The reverse of this idea, called the inbox pattern, removes duplicates on the receiving side, by recording each processed message's id in the very same transaction as the effect it caused.

Event sourcing stores the full sequence of events as the actual source of truth, and figures out the current state by replaying them from the start. In exchange, you get a complete audit trail, the ability to look at any point in the past, and the option to build entirely new views from that same history later. The cost is having to handle old event formats as your system evolves, needing periodic snapshots so replaying isn't unbounded, and the fact that a simple question like "what's the current balance" now requires computation instead of a lookup. Use this where the history genuinely is the product, like ledgers, audit trails, or collaborative documents, not as a default choice everywhere.

CQRS, short for command query responsibility segregation, splits the model you write to from one or more separate models you read from, kept in sync through events. It pairs naturally with event sourcing, and with any system whose reads look very different in shape from its writes, such as a normalised write side feeding a denormalised feed for reading. The cost is that the two sides can briefly disagree with each other, and you now maintain two models instead of one.

Change data capture, often shortened to CDC, reads a database's own internal change log directly, using a tool like Debezium on Postgres's write-ahead log or MySQL's binary log, and publishes each row change as an event. This gives you the outbox pattern's same safety without changing your application code at all, and it's the standard way to feed search indexes, caches, and data warehouses from one authoritative database.

Remember: writing to a database and publishing an event are two separate actions, so a crash between them loses one or the other. The outbox pattern writes the event into the same database transaction, so there is nothing to lose.

Sign in to try this knowledge check.

Quick recap

Queue jobs: decouple · buffer · async · retry.  Rule: response-independent work goes async.
Queue (RabbitMQ/SQS) = delete on ack, rich routing, per-message retry
Log   (Kafka)        = retained + replayable, many consumer groups, order PER PARTITION
                       partitions = max parallelism; partition key = ordering unit

Delivery: at-most-once (lossy) · at-least-once (DEFAULT, duplicates) · exactly-once (myth)
  → at-least-once + idempotent consumer = "effectively once"
  → idempotency via UNIQUE dedupe row, conditional UPDATE, or version check

Retries: exponential backoff + JITTER, capped, retryable vs permanent
DLQ after N failures + ALERT on depth (a poison message blocks its partition)
Backpressure: scale consumers → bound the queue → shed load → rate limit producers
Metric: consumer lag, and its TREND

Patterns: publish FACTS not commands · transactional OUTBOX (dual-write fix)
          inbox (consumer dedupe) · CDC (WAL → events) · event sourcing · CQRS
PreviousCAP, PACELC, and Levels of ConsistencyNextDistributed Transactions and Data Integrity

Course progress

0%
0 of 177 modules complete

On this page

  • Why a queue, and where the line goes
  • Queue vs log: the distinction that matters
  • Delivery semantics and idempotent consumers
  • Ordering, retries, dead letters, and backpressure
  • Event-driven patterns: pub/sub, outbox, event sourcing, CQRS
  • Quick recap