Asynchronous Communication with RabbitMQ - Slides
Instructor slide content for Unit 3: building production-ready async messaging with RabbitMQ, including durable queues and manual ACKs
SLIDE DECK: MODULE 03 - ASYNC COMMUNICATION (RABBITMQ) - V2.0 (PRODUCTION-READY)
Total Duration: 180 minutes (Concept/Lecture) Audience: Fresher/Employee (Completed Module 02)
Slide 1: Title Page
- Content:
- (Company / Training Unit Logo)
- MODULE 03: ASYNC COMMUNICATION
- From "Phone Calls" (Sync) to "Messages" (Async)
- Tools: RabbitMQ & Pika (Python)
- Trainer: (Your Name)
- Date: (Training Date)
- Visualization:
- Professional layout.
- Key visual: On one side, an [Icon: Phone call] with a hard connection line (representing Sync). On the other, an [Icon: Envelope/Message] flying towards a mailbox (representing Async).
- The RabbitMQ logo is in the corner.
- Instructor Script:
- "Welcome to Module 03. In Module 02, we learned how services 'call' each other in an organized way via the API Gateway. That is 'synchronous' communication—you call, and you must wait."
- "But what happens if the service you're calling is busy? Or down? Your entire system 'waits' or 'fails' along with it. Today, we'll learn a superior communication method to solve this: 'Asynchronous,' also known as 'sending a message.' You send the 'message' and immediately move on to other work, no waiting required."
- "Our tool for this is RabbitMQ, an extremely powerful 'Message Broker,' or 'post office'."
Slide 2: Session Agenda (Updated)
- Content:
- AGENDA (180 MINUTES)
- P1. The "Pain" of Synchronous Communication (~25 mins)
- P2. The Solution: Asynchronous Communication & Message Queues
- P3. Intro to RabbitMQ & Management UI (~15 mins) [Upgraded]
- P4. Core Concepts: "The Post Office Workflow" (~55 mins)
- Exchange, Queue, Binding & Routing Key
- Upgrade (Real-world): Durability, Persistence, Manual ACKs
- P5. Implementation (Python):
pikaProduction-Ready (~60 mins) [Upgraded]- Producer Code (Publisher Confirms, Persistence)
- Consumer Code (Manual ACK, Prefetch, NACK)
- P6. Best Practices & Lab Prep (~25 mins) [Upgraded]
- Visualization:
- A 6-step timeline. Parts P4 and P5 (the core theory + code) are highlighted most prominently.
- Instructor Script:
- "This is our agenda, upgraded to focus on real-world application. We'll still start with the 'pain' (P1, P2)."
- "In P3, we won't just introduce RabbitMQ; we will install it and see it working via the Management UI. P4 and P5 are the core; we'll learn the theory and code
pikafollowing 'production-ready' standards, meaning code that can 'survive' failures." - "Finally, P6 will summarize best practices (like DLQ, Idempotency) and introduce Assignment 3."
Slide 3: Learning Objectives
- Content:
- OBJECTIVES (AFTER THIS MODULE, YOU WILL BE ABLE TO...)
- 1. Distinguish: Clearly articulate the pros/cons of Sync vs. Async and when to use each.
- 2. Define: Explain the 4 core AMQP concepts: Exchange, Queue, Binding, and Routing Key.
- 3. Implement: Write a safe
Producer(durable, persistent, publisher confirms). [Upgraded] - 4. Implement: Write a safe
Consumer(manual ack, prefetch, nack) to ensure "at-least-once delivery." [Upgraded]
- Visualization:
- 4 icons: [Icon: Scales/Balance (Distinguish)], [Icon: Dictionary (Define)], [Icon: Safe Send (Implement Producer)], [Icon: Safe Receive (Implement Consumer)].
- Instructor Script:
- "This is my commitment to you. After this module, you won't just 'write code'; you'll 'write safe code'."
- "You will understand why
auto_ack=Trueis a terrible idea, whydelivery_mode=2is mandatory, and how to handle it when your consumer fails without losing the message. This is 'survival' knowledge for real projects."
Slide 4: Module 02 Recap
- Content:
- RECAP: WHERE ARE WE?
- Module 02: Client calls the API Gateway (Kong). Kong "routes" the request to the internal service (e.g.,
User Service). - Communication Type: Synchronous.
[Client] -> [Kong] -> [User Service]- Problem: The Client (and Kong) must wait for the
User Serviceto finish processing and return a response.
- Visualization: *
[Image of synchronous API call via API Gateway]
* A simple diagram from Module 02. An arrow goes from Client -> Kong -> Service, and a (Response) arrow goes back. An [Icon: Hourglass (Waiting)] is shown at the Client.- Instructor Script:
- "Let's remember Module 02. We successfully configured Kong. The Client 'calls' Kong, Kong 'transfers the call' to the User Service. This is synchronous communication."
- "But what's the problem? The Client has to 'hold the line' (wait) until the User Service answers. If the User Service is busy, the Client waits. If the User Service 'drops the call' (crashes), the Client's call fails too. This is 'Tight Coupling'."
Slide 5: Section Intro - P1 & P2: Understanding Communication Patterns
- Content:
- PART 1 & 2
- UNDERSTANDING COMMUNICATION PATTERNS
- The "Pain" of Synchronous Communication
- The Solution: Asynchronous Communication
- Visualization:
- Professional layout with section number and title.
- Visual: Split screen showing [Icon: Phone call with chain/lock (Sync Pain)] on left and [Icon: Envelope with wings (Async Solution)] on right.
- Instructor Script:
- "In this first section, we'll explore the fundamental problem that async communication solves."
- "We'll start by experiencing the 'pain' of synchronous communication through a real-world scenario, then see how asynchronous communication elegantly solves these problems."
Slide 6: P1 - The "Pain" of Synchronous Communication (Sync)
- Content:
- SCENARIO: PLACING AN ORDER (SYNC)
- User clicks "Place Order." The request goes to
Order Service. Order Service(Sync) must do 4 things in a row:- Call
Payment Service-> Wait... - Call
Inventory Service(Deduct stock) -> Wait... - Call
Notification Service-> Wait... - Call
Email Service-> Wait... - Return "OK" to the User.
- Call
- "THE PAIN":
- High Latency: The User has to wait (e.g., 10 seconds) for all sub-services to finish. Bad experience.
- Tight Coupling: All 4 other services must be "alive."
- Cascading Failure: If the
Email Service(low priority) fails -> The entire "Place Order" transaction (high priority) fails.
- Visualization: *
- A "domino chain" diagram:
User -> [Order] -> [Payment] -> [Inventory] -> [Notification] -> [Email (Crashes - X)]- When the last service (Email) falls, it makes the entire chain (including Order) fall with it.
- Instructor Script:
- "Let's look at this nightmare scenario. A user places an order. Our
Order Servicehas to 'synchronously call' 4 other services. The user has to 'hold the line' for 10 seconds." - "But the real disaster is this: [Point to diagram] The
Email Service(the least important one) fails. What happens? The entire 'call' fails.Order Servicereturns an error. The user cannot place an order just because... the email service is down. This is a 'Cascading Failure' and an unacceptable design."
- "Let's look at this nightmare scenario. A user places an order. Our
Slide 7: P2 - The Solution: Asynchronous Communication (Async)
- Content:
- SCENARIO: PLACING AN ORDER (ASYNC)
- User clicks "Place Order." The request goes to
Order Service. Order Service(Async) only does 2 things:- Save the order to its DB (status:
Pending). - "Send a message" (Event) named
OrderPlacedto a "Post Office" (Message Broker). - Return "OK" (e.g., 0.1 seconds) to the User.
- Save the order to its DB (status:
- Later (in the background):
Payment Service(listens for)OrderPlaced-> Processes it.Inventory Service(listens for)OrderPlaced-> Processes it.Notification Service(listens for)OrderPlaced-> Processes it.
- THE BENEFITS:
- Low Latency: The user gets an immediate response.
- Loose Coupling:
Order Servicedoes not know or care who is listening. - Resilience: If the
Email Serviceis down? Who cares. The message is safe in the "Post Office." When theEmail Service"wakes up," it will process the message. The order still succeeds.
- Visualization: *
- A "clean" Pub/Sub diagram:
User -> [Order Service](Returns OK immediately)[Order Service]-> sends 1 message to[Message Broker (RabbitMQ)]- From the
[Message Broker], 3 independent arrows shoot out:-> [Payment Service]-> [Inventory Service]-> [Notification Service](This service can be down - X - but it doesn't affect the others).
- Instructor Script:
- "Now let's do it right. The Async scenario. [Point to diagram] User places an order. Order Service does two things: save to DB, and 'throw' a 'package' (message) named
OrderPlacedinto the 'Post Office' (Message Broker). Done! It returns OK to the user immediately." - "While the user is happy, in the 'background,' other services (Payment, Inventory, Notification) are 'mail subscribers.' They go to the 'Post Office' on their own, pick up their 'copy' of the message, and process it."
- "What's the benefit? [EMPHASIZE] If the Notification Service is down? No problem!
OrderandPaymentstill run. The message forNotificationwill 'wait' safely in the 'Post Office.' When that service wakes up, it will fetch the message and continue. Our system just became 'resilient'."
- "Now let's do it right. The Async scenario. [Point to diagram] User places an order. Order Service does two things: save to DB, and 'throw' a 'package' (message) named
Slide 8: Section Intro - P3: Introduction to RabbitMQ
- Content:
- PART 3
- INTRODUCTION TO RABBITMQ
- Setting Up Your Message Broker
- Management UI & Docker Installation
- Visualization:
- Professional layout with section number and title.
- Visual: RabbitMQ logo with [Icon: Docker container] and [Icon: Dashboard/Management UI].
- Instructor Script:
- "Now that we understand WHY we need async communication, let's meet our tool: RabbitMQ."
- "In this section, we'll install RabbitMQ using Docker and explore its powerful Management UI that will help us observe messages in real-time."
Slide 9: P3 - Intro to RabbitMQ & Management UI (UPGRADED)
-
Content:
- PART 3: INTRO TO RABBITMQ
- What is it? A "Message Broker" (Post Office).
- It's middleware that lets services communicate without knowing about each other.
- What does it do? Receives, stores (safely), and forwards messages.
- What protocol? AMQP (Advanced Message Queuing Protocol) - a standard "language" for talking to "post offices."
- What library (Python)?
pika - Installation (Lab): Using
docker-compose
# docker-compose.yml services: rabbitmq: image: rabbitmq:3-management-alpine container_name: 'rabbitmq' ports: - '5672:5672' # AMQP protocol port - '15672:15672' # Management UI port volumes: - ~/.docker-conf/rabbitmq/data/:/var/lib/rabbitmq/ - ~/.docker-conf/rabbitmq/log/:/var/log/rabbitmq- Management UI (VERY IMPORTANT):
- After
docker-compose up, access: http://localhost:15672(user/pass:guest/guest)- This is where we Observe Exchanges, Queues, and message counts.
- After
-
Visualization: *
- On the left, the
docker-compose.ymlcode block. - On the right, a screenshot of the RabbitMQ Management UI, with "Queues" tab and the "Ready" / "Unacked" columns circled in red.
- On the left, the
-
Instructor Script:
- "This is our 'Post Office,' RabbitMQ. We'll install it with Docker. Note this
docker-compose.ymlfile; I'm using therabbitmq:3-managementimage. That 'management' tag is extremely important." - "It opens two ports: 5672 for our
pikacode to talk to, and 15672 for us." - "[Point to UI screenshot] Right now, I want you to
docker-compose upand accesshttp://localhost:15672. This is the 'security camera' for our post office. Throughout this module, we will keep coming back here to see messages move, get 'stuck' (Unacked), or 'wait' (Ready)."
- "This is our 'Post Office,' RabbitMQ. We'll install it with Docker. Note this
Slide 10: Section Intro - P4: Core Concepts
- Content:
- PART 4
- CORE CONCEPTS: "THE POST OFFICE WORKFLOW"
- Exchange, Queue, Binding & Routing Key
- Durability, Persistence, Manual ACKs
- Visualization:
- Professional layout with section number and title.
- Visual: [Icon: Building/Post Office] with key elements labeled: Exchange (Sorting Room), Queue (P.O. Box), Binding (Rules).
- Instructor Script:
- "This is the heart of RabbitMQ. We need to understand how messages flow through the system."
- "Think of RabbitMQ as a sophisticated post office. We'll learn about the Sorting Room (Exchange), the P.O. Boxes (Queues), and the routing rules (Bindings) that connect them."
Slide 11: P4 - Core Concepts: "The Post Office Workflow"
- Content:
- CORE RABBITMQ CONCEPTS
- To understand RabbitMQ, forget code and imagine a post office:
- Producer (Sender): The person writing the letter.
- Consumer (Receiver): The person waiting for the letter.
- Message (Letter): The letter (the data packet).
- And the 3 most important AMQP concepts:
- Exchange (The Sorting Room): Where the letter first arrives.
- Queue (The P.O. Box): Where the letter is stored waiting to be picked up.
- Binding (The Forwarding Request Form): The rule that connects an Exchange to a Queue.
- Visualization:
- A simple overview diagram:
[Producer] -> [Exchange] -> [Binding] -> [Queue] -> [Consumer]
- Instructor Script:
- "This is the most important part. To understand RabbitMQ, you must understand these 3 concepts. I'll use the Post Office analogy."
- "The Producer is you (the sender). The Consumer is the receiver."
- "But here's the 'brain-twist': You (the Producer) never send a letter directly to the receiver's 'mailbox' (Queue). You always send your letter to the 'Sorting Room' (Exchange). It is the 'Sorting Room's' job to read the 'forwarding request' (Binding) and decide which 'P.O. Box' (Queue) to put the letter in."
- "Let's look at these 3 concepts."
Slide 12: Concept #1: Exchange (The Sorting Room)
- Content:
- EXCHANGE (THE SORTING ROOM)
- What is it? The entity where the Producer sends the message.
- Its Job: To receive messages and "route" them to one or more Queues.
- How does it route? Based on its
Exchange Typeand the message'sRouting Key(next slide). - Common Types:
- Fanout (Broadcast): Simplest. Sends a copy of the message to all Queues bound to it. (Ignores Routing Key).
- Direct: Routes the message to the Queue whose
Binding Keyexactly matches the message'sRouting Key. - Topic: Routes if the
Routing Keymatches the pattern of theBinding Key(e.g.,user.created.*).
- UPGRADE (Real-world): Durability
durable=True: This Exchange must survive a RabbitMQ restart. (If not, the Exchange vanishes, bindings vanish -> message loss).- Rule: Always set
durable=Truefor Exchanges in production.
- Visualization: *
- A visual diagram of the 3 Exchange types (Fanout, Direct, Topic).
- Add an [Icon: Hard Drive/Save (Durable)] to the corner of the slide.
- Instructor Script:
- "The Exchange is the 'reception desk' of the post office. You (the Producer) send your letter here. The Exchange 'sorts' the mail."
- "It has several 'types'. The 'Fanout' type is like a 'broadcast'—it gets a message and 'shouts' it to all mailboxes (Queues) that are subscribed."
- "The 'Direct' type is smarter. It looks at the 'stamp' (Routing Key) on your letter, e.g., 'Finance.' It will 'forward' this letter only to the mailbox (Queue) that registered for the 'Finance' stamp. We will use 'Direct' or 'Topic' most."
- "And here is our first production upgrade: 'Durability.' When you declare an Exchange, you must add
durable=True. This tells RabbitMQ to 'write' this Exchange to the 'hard drive.' If you don't, and RabbitMQ restarts, your 'in-memory' Exchange 'evaporates,' all your 'rules' (bindings) are lost, and all messages sent to it will 'disappear'."
Slide 13: Concept #2 & #3: Queue & Binding
- Content:
- QUEUE (THE P.O. BOX)
- What is it? The buffer that stores messages until a Consumer is ready.
- This is the actual "mailbox."
- The Consumer connects to and listens from the Queue.
- UPGRADE (Real-world): Durability
durable=True: This Queue (and its persistent messages) must survive a RabbitMQ restart.- Rule: Always set
durable=Truefor Queues in production.
- BINDING (THE FORWARDING REQUEST FORM)
- What is it? A "relationship," a "rule."
- It tells an Exchange: "Hey Exchange, if you get a letter with
Routing Key=user.created, please forward a copy toemail_queue." - Conclusion: The Exchange (reception) and the Queue (storage) are linked by the Binding.
- QUEUE (THE P.O. BOX)
- Visualization: *
- A clear diagram:
[Exchange (durable)]and[Queue (durable)]are two separate entities. The[Binding (Rule)]is the arrow connecting them. Both Exchange and Queue have the [Icon: Hard Drive/Save (Durable)].
- A clear diagram:
- Instructor Script:
- "The Queue is the 'P.O. Box.' It's what 'holds' the mail. The Consumer has the 'key' to this box and comes to pick up mail."
- "And just like the Exchange, the Queue must be
durable=True. If not, RabbitMQ restarts, the 'mailbox' evaporates, and all the messages inside (even 'persistent' ones) are 'lost'." - "The Binding is the 'rule' that connects the Exchange (reception) to the Queue (storage). It's that simple."
Slide 14: The Full Flow & Persistence (UPGRADED)
- Content:
- THE FULL (PRODUCTION) WORKFLOW
- 1. (Producer): Sends a Message with:
Routing Key="user.created"delivery_mode=2(Tells RabbitMQ to save this message to disk)- To the
Exchange(durable=True).
- 2. (Exchange): Receives message. Checks its 'Binding' rulebook.
- 3. (Binding): Sees rule: "user.created" ->
email_queue. - 4. (Queue): Exchange routes a copy of the message to
email_queue(durable=True). RabbitMQ writes the message to disk because ofdelivery_mode=2. - 5. (Consumer):
Email Service(listening toemail_queue) receives the message (respecting prefetch).- Processes it (sends email).
- Sends a
basic_ack(Manual Acknowledgment).
- 6. (Queue): RabbitMQ receives the
ack-> Deletes the message from the Queue.
- Visualization: *
- The same flow diagram as before, but with new "annotations":
- Arrow (1):
(delivery_mode=2) - Block (4) Queue:
(Message is Persisted to Disk) - Arrow (5):
(auto_ack=False) - A new (reverse) Arrow (6):
(basic_ack)
- Arrow (1):
- The same flow diagram as before, but with new "annotations":
- Instructor Script:
- "This is the 'production-ready' flow. It's more complex but 'immortal'. Step 1, the Producer doesn't just 'send'; it 'sends' with the property
delivery_mode=2. This is a 'waterproof letter,' telling RabbitMQ to 'save to disk'." - "Step 4, the (durable) Queue receives this 'waterproof letter' and stores it safely."
- "Step 5, the Consumer receives the message. But [IMPORTANT], RabbitMQ does not delete the message yet (because we turned off
auto_ack). It just 'temporarily hides' it. On the UI, this message will be in the 'Unacked' column." - "Step 6, after the Consumer is finished processing (email sent), it sends back an 'OK' signal (
basic_ack). Only then does RabbitMQ actually delete the message. If the Consumer 'crashes' before sending theack, RabbitMQ will 'un-hide' that message and deliver it to another consumer. This is 'at-least-once delivery'."
- "This is the 'production-ready' flow. It's more complex but 'immortal'. Step 1, the Producer doesn't just 'send'; it 'sends' with the property
Slide 15: Section Intro - P5: Implementation with Python
- Content:
- PART 5
- IMPLEMENTATION (PYTHON) WITH
pika - Production-Ready Producer Code
- Production-Ready Consumer Code
- Visualization:
- Professional layout with section number and title.
- Visual: [Icon: Python logo] + [Icon: Code/Terminal] with arrows showing Producer -> RabbitMQ -> Consumer.
- Instructor Script:
- "Theory is important, but now it's time to write real code."
- "In this section, we'll implement both Producer and Consumer using the
pikalibrary, following production-ready standards that ensure messages are never lost."
Slide 16: P5 - Implementation (Python) with pika (UPGRADED)
- Content:
- PART 5
- IMPLEMENTATION (PYTHON) WITH
pika(PRODUCTION-READY) pika: The most popular Python client.- We will upgrade 2 scripts to ensure:
producer.py: Messages aren't "lost" on send (Publisher Confirms, Persistence). [Upgraded]consumer.py: Messages aren't "lost" on consumer failure (Manual ACKs, Prefetch, NACK). [Upgraded]
- Visualization:
- Split slide into 2 columns:
- Column 1: [Icon: Safe Send (Producer)] +
confirm_delivery(),delivery_mode=2. - Column 2: [Icon: Safe Receive (Consumer)] +
auto_ack=False,basic_ack.
- Column 1: [Icon: Safe Send (Producer)] +
- Split slide into 2 columns:
- Instructor Script:
- "Now for the code. We're going to look at the 2 producer/consumer files that have been 'upgraded' to handle the problems we just discussed."
Slide 17: Implementation: producer.py (UPGRADED)
-
Content:
producer.py(THE SAFE SENDER)
import pika, json connection = pika.BlockingConnection(pika.ConnectionParameters('localhost')) channel = connection.channel() # UPGRADE 1: Enable Publisher Confirms (to know RabbitMQ got it) channel.confirm_delivery() # UPGRADE 2: Declare a DURABLE Exchange channel.exchange_declare(exchange='user_exchange', exchange_type='topic', durable=True) routing_key = 'user.created' message = { 'user_id': 123, 'email': 'example@gmail.com' } # UPGRADE 3: Send a PERSISTENT message (delivery_mode=2) props = pika.BasicProperties(content_type='application/json', delivery_mode = pika.spec.PERSISTENT_DELIVERY_MODE) try: channel.basic_publish( exchange='user_exchange', routing_key=routing_key, body=json.dumps(message), properties=props, mandatory=True # Fail if no queue is bound to route to ) print(f" [x] Sent '{routing_key}':'{message}'") except pika.exceptions.UnroutableError: print(" [!] Message was unroutable. Check exchange or binding.") connection.close() -
Visualization:
- A code block with the 3 "UPGRADES" highlighted in yellow.
-
Instructor Script:
- "This is the new Producer code. It has 3 upgrades."
- "1.
confirm_delivery(): This turns on 'receipts'. Afterbasic_publish, we can (in theory) wait for RabbitMQ to 'confirm' it received the message. (In Blocking code, it will raise an exception if it fails)." - "2.
durable=Truefor the Exchange, as discussed." - "3. Most important:
delivery_mode=2(Persistent). This is the 'save to disk' command. Without this, a RabbitMQ restart means message loss."
Slide 18: Implementation: consumer.py (UPGRADED)
-
Content:
consumer.py(THE SAFE RECEIVER)
import pika, json, time connection = pika.BlockingConnection(pika.ConnectionParameters('localhost')) channel = connection.channel() channel.exchange_declare(exchange='user_exchange', exchange_type='topic', durable=True) # UPGRADE 1: Declare a DURABLE Queue result = channel.queue_declare(queue='email_queue', durable=True) queue_name = result.method.queue binding_key = 'user.*' channel.queue_bind(exchange='user_exchange', queue=queue_name, routing_key=binding_key) # UPGRADE 2: Only fetch 10 messages at a time (QoS) channel.basic_qos(prefetch_count=10) # UPGRADE 3: Process message and ACK/NACK manually def callback(ch, method, properties, body): message = json.loads(body) print(f" [x] Received {method.routing_key}: {message}") try: # Simulate 5s of work (sending email...) time.sleep(5) print(" [x] Done processing.") # UPGRADE 4: Tell RabbitMQ: "Done, you can delete it" (ACK) ch.basic_ack(delivery_tag=method.delivery_tag) except Exception as e: print(f" [!] Error processing: {e}") # UPGRADE 5: Tell RabbitMQ: "Failed, don't resend" (NACK) # (requeue=False -> send to Dead-Letter-Exchange if configured) ch.basic_nack(delivery_tag=method.delivery_tag, requeue=False) # UPGRADE 6: Turn OFF "Auto-delete" (auto_ack=False) channel.basic_consume(queue=queue_name, on_message_callback=callback, auto_ack=False) print(' [*] Waiting for messages...') channel.start_consuming() -
Visualization:
- A code block with the 6 "UPGRADES" highlighted.
-
Instructor Script:
- "This is the 'money' slide. The safe Consumer code."
- "1 & 2: Declare a
durable=TrueQueue andbasic_qos(prefetch_count=10). Prefetch says: 'Don't send me 1 million messages at once, I'll crash. Send me 10 at a time. When I finish one, I'll take the next'." - "6. [MOST IMPORTANT]
auto_ack=False. This turns off auto-delete. Now, when RabbitMQ delivers a message, it still 'holds' a 'temporary' copy (Unacked)." - "4. Inside the
callback, after successful processing, we callbasic_ack(Acknowledge) to say 'I'm done, you can delete it now'." - "5. If our code fails (Exception), we call
basic_nack(Negative Ack) andrequeue=False. This means: 'I failed, don't give it back to me (it will fail again), throw it in a 'dead-letter' queue'."
Slide 19: P5 (Continued) - Sync vs. Async: Decision Flowchart (UPGRADED)
- Content:
- SYNC VS. ASYNC: DECISION FLOWCHART
- When designing a feature, ask yourself this:
- Flowchart:
- [Start] Does the Client need an immediate response to display?
- [YES] -> USE SYNC (API CALL) (e.g.,
GET /user,POST /login). - [NO] (Client just needs "OK, got it"?) -> Continue.
- Is this task time-consuming (> 1s) or can it fail (calls 3rd party)? (e.g., Send email, resize image, place order).
- [YES] -> USE ASYNC (MESSAGE QUEUE) (e.g.,
POST /order-> SendOrderPlacedEvent). - [NO] (Task < 1s, low-risk) -> Consider Sync (for simplicity) or Async (for decoupling).
- Visualization:
- A simple flowchart as described above, using diamonds (Decision) and rectangles (Process).
- Instructor Script:
- "This is a flowchart to help you 'choose your weapon.' The first and most important question: Does the client need an answer NOW?"
- "If YES (e.g., 'get me user 123's info'), you must use SYNC. Never do 'RPC over MQ' (using a message queue to simulate Sync); it's slow and complex."
- "If NO (e.g., 'place this order,' 'send this email'), ask the next question: Is the task 'heavy' or 'risky'? If YES, you must use ASYNC. This will be 90% of your cases."
Slide 20: Section Intro - P6: Best Practices & Lab Prep
- Content:
- PART 6
- BEST PRACTICES & LAB PREP
- Dead-Letter-Exchange (DLX)
- Idempotent Consumers
- Assignment 03
- Visualization:
- Professional layout with section number and title.
- Visual: [Icon: Checklist/Best Practices] + [Icon: Lab/Assignment] + [Icon: Advanced patterns].
- Instructor Script:
- "Before we wrap up, let's cover critical best practices that separate toy projects from production systems."
- "We'll also introduce Assignment 03, where you'll apply everything you've learned to build a production-ready async communication system."
Slide 21: P6 - Best Practices (UPGRADED)
- Content:
- PART 6: BEST PRACTICES & LAB PREP
- 1. Dead-Letter-Exchange (DLX) - The "Failed Mail" Queue
- When a Consumer
nack(requeue=False), where does the message go? - Configure your Queue to "route" nack-ed messages to a special "dead-letter" Exchange (DLX), which is bound to a "dead-letter" Queue (DLQ).
- This allows you to re-process failed messages later, instead of losing them.
- When a Consumer
- 2. Idempotent Consumers - The "Memoizing" Consumer
- Because of "At-least-once" delivery, a Consumer might receive the same message twice.
- Your Consumer must be "idempotent": processing message
ID 1235 times is the same as processing it 1 time. - How: Check a DB if
message_idhas already been processed.
- 3. Anti-Pattern: Large Payloads
- Message Queues are not S3/databases.
- DON'T put a 10MB image file in a message.
- DO: Upload the file to S3/blob storage, and send the S3 link (pointer) in the message.
- Visualization: *
- Three icons: [Icon: Recycle Bin/Ambulance (DLX)], [Icon: Repeated number 1 (Idempotent)], [Icon: Large file with X (Anti-Pattern)].
- Instructor Script:
- "Before the Lab, here are 3 advanced best practices. One, when you 'nack' (reject) a message, configure a DLX. This is the 'graveyard' for failed messages. We can write another tool to 'dig through the graveyard' (the DLQ) and retry them later."
- "Two, 'Idempotent.' The system guarantees 'at-least-once,' which means it could be 2-3 times. Your code must be 'immune.' If user A places order
ID 123, and your consumer gets this message 3 times, it must only deduct inventory 1 time." - "Three, never put a 10MB file in RabbitMQ. Upload the file to S3/MinIO, and just 'send the link' in the message."
Slide 22: P6 - Lab Prep: Assignment 03 (UPGRADED)
- Content:
- IMPLEMENTATION LAB (ASSIGNMENT 03)
- Mission: Integrate RabbitMQ into
User Service(Production-Ready). - Requirements:
- Provide
docker-compose.ymlto runrabbitmq:3-management-alpine. - Modify
User Service(Producer): OnPOST /users(create user), publish aUserCreatedmessage. - Create
email_consumer.pyscript (Consumer): Listen forUserCreatedand print.
- Provide
- PASS/FAIL CRITERIA (CHECKLIST): [Upgraded]
[ ]Exchange and Queue must bedurable=True.[ ]Message must be sent withdelivery_mode=2(Persistent).[ ]Consumer must useauto_ack=Falseand callbasic_ackmanually.[ ]Consumer usesbasic_qos(prefetch_count>=1).[ ](Bonus): Configure a DLX/DLQ for the consumer on a purposefulraise Exception.[ ]Submit with: A screenshot of the RabbitMQ Management UI (:15672) showing your durable Exchange, Queue, and "Ready" / "Unacked" messages.
- Visualization: *
- The lab's architecture diagram:
[Postman] -> [User Service (Producer)] -> (Persistent Msg) -> [RabbitMQ (Durable)][RabbitMQ (Durable)] -> (Manual Ack) -> [Email Consumer (Script)]- A checklist (as above) takes up 1/3 of the slide.
- Instructor Script:
- "This is your mission for Assignment 03. You will integrate a Producer into your
User Serviceand write a separate Consumer." - "And this is the 'grading rubric.' [Point to Checklist] I don't just care if your code 'runs.' I care if it's 'safe.' You must prove your messages are 'durable,' and your consumer 'acks manually.' Use the
localhost:15672UI to observe this. Put atime.sleep(30)in your consumer, and you'll see the message get 'stuck' in 'Unacked.' That is proof you're doing it right."
- "This is your mission for Assignment 03. You will integrate a Producer into your
Slide 23: Case Study #1 - E-commerce Order Notification System
- Content:
- REAL-WORLD: E-COMMERCE ORDER CONFIRMATION (SHOPEE/AMAZON)
- Scenario: Customer places an order → System must send confirmation email, SMS, and push notification.
- Why NOT Synchronous?
- If
POST /orderscallsEmailServicesynchronously:- Customer waits 5 seconds for email to send (bad UX).
- If
EmailServiceis down, the entire order fails (cascading failure). - If email provider (SendGrid) has rate limits → order API becomes slow.
- If
- Async Solution with RabbitMQ:
Order Service(Producer):- Saves order to DB (status:
PENDING). - Publishes
OrderCreatedevent to RabbitMQ (durable, persistent). - Returns
200 OKto customer immediately (< 100ms).
- Saves order to DB (status:
Email Consumer:- Listens for
OrderCreatedevents. - Sends confirmation email asynchronously.
- If fails → message goes to DLQ, retries later.
- Listens for
SMS Consumer:- Listens for
OrderCreatedevents. - Sends SMS notification asynchronously.
- Listens for
Push Notification Consumer:- Listens for
OrderCreatedevents. - Sends push notification to mobile app.
- Listens for
- Production Benefits:
- ✅ Fast Response: Customer gets
200 OKinstantly (99th percentile < 100ms). - ✅ Resilient: If Email service is down, order still succeeds. Email is retried later.
- ✅ Decoupled: Adding a new consumer (e.g., Slack notification) doesn't require changing
Order Service. - ✅ Scalable: Can scale Email/SMS/Push consumers independently based on load.
- ✅ Fast Response: Customer gets
- Key Metrics (Real Production):
- Order API Response Time: 50ms (was 5 seconds with Sync).
- Email Delivery Rate: 99.9% (with DLQ retry).
- System Uptime: 99.99% (Email downtime doesn't affect orders).
- Visualization:
- Diagram showing:
- Top: Synchronous (Bad) -
[Client] → [Order Service] → [Email Service (5s)] → [Client waits] - Bottom: Asynchronous (Good) -
[Client] → [Order Service (100ms)] → [RabbitMQ]then[RabbitMQ] → [Email Consumer],[SMS Consumer],[Push Consumer](all parallel)
- Top: Synchronous (Bad) -
- Highlight: Clock icon showing time savings (5s → 100ms)
- Diagram showing:
- Instructor Script:
- "Let's see how real companies use RabbitMQ. This is Shopee/Amazon's order confirmation flow."
- "[Point to Sync diagram] In the old days, when you placed an order, the API would wait for the email to send. 5 seconds of waiting. Terrible user experience."
- "[Point to Async diagram] With RabbitMQ, the Order Service saves the order, publishes one event, and returns '200 OK' in 100 milliseconds. The customer is happy."
- "Behind the scenes, three separate consumers (Email, SMS, Push) all 'hear' this event and do their work in parallel. If the Email service is down, the order still succeeds. The email just goes to the DLQ and is retried later."
- "This is how you build systems that are both fast and resilient."
Slide 24: Case Study #2 - Banking Transaction Audit Logging
- Content:
- REAL-WORLD: FINANCIAL TRANSACTION AUDIT TRAIL (BANK/FINTECH)
- Scenario: Every bank transaction must be logged for compliance/audit (regulatory requirement).
- Why NOT Synchronous?
- If
POST /transfercallsAuditServicesynchronously:- Transfer API becomes slower (adds 200ms+ latency).
- If
AuditServiceis down → entire banking system is down (unacceptable). - Regulatory Risk: If audit log fails, the transaction might still succeed → compliance violation.
- If
- Async Solution with RabbitMQ:
Transfer Service(Producer):- Executes the transfer (debit Account A, credit Account B) in a local transaction.
- Publishes
TransactionCompletedevent to RabbitMQ (durable, persistent) in the same transaction (Transactional Outbox Pattern). - Returns
200 OKto client.
Audit Consumer:- Listens for
TransactionCompletedevents. - Writes to immutable audit log (Elasticsearch / Append-only DB).
- Uses manual ack to guarantee "at-least-once" delivery.
- Critical: If audit write fails, message goes to DLQ → alerts are triggered → humans investigate.
- Listens for
- Production Benefits:
- ✅ Fast Transfers: Transfer API latency remains low (< 100ms).
- ✅ Resilient: If Audit service is down, transfers still work. Audit logs are written when it comes back up.
- ✅ Guaranteed Delivery: RabbitMQ's persistence + manual ack ensures zero audit logs are lost (compliance requirement).
- ✅ Async Compliance: Regulators accept "eventual audit" (logs written within 5 seconds) as compliant.
- Key Metrics (Real Production):
- Transfer API Latency: 80ms (was 300ms with Sync).
- Audit Log Completeness: 100% (zero lost logs in 2 years).
- System Availability: 99.999% (Audit downtime doesn't affect transfers).
- Critical Pattern: Transactional Outbox
- The Transfer Service doesn't call RabbitMQ directly.
- It saves the event to an
OUTBOXtable in the same DB transaction as the transfer. - A separate "Relay" process reads the
OUTBOXand publishes to RabbitMQ. - This guarantees: If the transfer succeeds, the event will be published (no dual-write problem).
- Visualization:
- Diagram showing:
[Transfer Service] → [DB: Transfer + OUTBOX](same transaction)[Relay Process] → reads OUTBOX → [RabbitMQ][RabbitMQ] → [Audit Consumer] → [Audit Log (Immutable)]
- Highlight: "Transactional Outbox Pattern" box
- Diagram showing:
- Instructor Script:
- "Another critical use case: banking audit logs."
- "In banking, every transaction must be logged. This is a regulatory requirement. If you lose a log, you can be fined millions of dollars."
- "[Point to diagram] The naive approach: Call the Audit service synchronously. But if the Audit service is down, your entire banking system is down. Unacceptable."
- "The smart approach: Use RabbitMQ. The Transfer service publishes an event, and the Audit consumer writes the log asynchronously."
- "But here's the critical pattern: Transactional Outbox. [Point to OUTBOX table] The Transfer service doesn't call RabbitMQ directly. It saves the event to a table in the same transaction as the transfer. A separate 'Relay' process publishes it to RabbitMQ."
- "This guarantees: If the transfer succeeds, the audit log will be written. No dual-write problem. This is how you build systems that regulators trust."
Slide 25: Best Practices Checklist (Expanded)
- Content:
- ASYNC COMMUNICATION: PRODUCTION BEST PRACTICES
- ✅ DO (8 Critical Practices):
- Durable Exchanges & Queues: Always use
durable=True. Queues/Exchanges survive RabbitMQ restarts. - Persistent Messages: Always use
delivery_mode=2. Messages survive RabbitMQ restarts. - Manual Acknowledgment: Always use
auto_ack=Falseand callbasic_ack()manually. Prevents message loss on consumer crash. - Prefetch Limit: Always use
basic_qos(prefetch_count=1-10). Prevents one consumer from hogging all messages. - Dead-Letter-Exchange (DLX): Configure DLX for every queue. Failed messages go to DLQ for investigation/retry.
- Idempotent Consumers: Design consumers to be idempotent. "At-least-once" delivery means duplicates are possible.
- Message TTL & Timeouts: Set
x-message-ttlon queues. Prevents "zombie messages" from clogging the system. - Publisher Confirms: Use
confirm_delivery()in Pika. Ensures RabbitMQ received the message.
- Durable Exchanges & Queues: Always use
- ❌ DON'T (6 Common Pitfalls):
- Large Payloads: Don't send large files (> 1MB) in messages. Upload to S3/MinIO, send the link.
- Auto-Ack: Never use
auto_ack=Truein production. You will lose messages on consumer crash. - Non-Durable: Never use
durable=Falsefor queues/exchanges. You will lose messages on RabbitMQ restart. - Ignoring NACK/DLQ: Don't just
nack(requeue=False)and forget. Investigate DLQ messages. - RPC over MQ: Don't use RabbitMQ for synchronous request/reply (RPC pattern). Use HTTP/gRPC instead.
- No Monitoring: Don't deploy without monitoring. Use RabbitMQ Management UI + Prometheus to track queue depth, consumer lag.
- PRODUCTION CHECKLIST:
[ ]All exchanges/queues aredurable=True?[ ]All messages sent withdelivery_mode=2?[ ]All consumers useauto_ack=False+ manualbasic_ack()?[ ]All consumers havebasic_qos(prefetch_count)set?[ ]DLX/DLQ configured for all critical queues?[ ]Consumers are idempotent (handle duplicate messages)?[ ]Message TTL configured to prevent queue buildup?[ ]Monitoring/alerting in place (queue depth, consumer lag)?
- Visualization:
- A 2-column layout:
- Left: ✅ DO (Green checkmarks)
- Right: ❌ DON'T (Red X marks)
- Bottom: Production Checklist (with checkboxes)
- A 2-column layout:
- Instructor Script:
- "Before you deploy to production, let's review the complete best practices checklist."
- "[Point to DO list] These 8 practices are mandatory. They are the difference between a system that works in production and a system that loses data at 3 AM."
- "Number 2: Persistent messages. If you don't set
delivery_mode=2, your messages disappear when RabbitMQ restarts. I've seen companies lose millions of dollars because of this one mistake." - "Number 3: Manual ack. If you use
auto_ack=True, RabbitMQ assumes your message was processed as soon as your consumer receives it. If your consumer crashes 1 second later, the message is gone forever." - "[Point to DON'T list] And these are the 'land mines' you must avoid."
- "Number 2: Auto-Ack. This is the most common mistake I see. Developers use it because it's 'easier.' But in production, it causes data loss."
- "[Point to Checklist] This is your production readiness checklist. Before you deploy, check all 8 boxes. If you can't check them all, you're not ready."
Slide 26: When to Use Async? (Decision Framework)
- Content:
- DECISION FRAMEWORK: ASYNC vs. SYNC
- When to Use ASYNC (Message Queue)?
- ✅ Fire-and-Forget Operations:
- Sending emails, SMS, push notifications.
- Logging, analytics, audit trails.
- Generating reports, thumbnails, PDFs.
- ✅ Decoupling Services:
- Producer doesn't care who consumes the message.
- Adding new consumers doesn't require changing the producer.
- ✅ Load Leveling / Peak Handling:
- Producer publishes 1000 messages/second.
- Consumers process 100 messages/second.
- RabbitMQ acts as a buffer (queue absorbs spikes).
- ✅ Resilience / Fault Tolerance:
- If the consumer is down, messages are queued.
- When the consumer comes back up, it processes the backlog.
- ✅ Long-Running Tasks:
- Video transcoding, ML model training, data processing.
- Don't make the client wait for 10 minutes.
- ✅ Fire-and-Forget Operations:
- When to Use SYNC (HTTP/gRPC)?
- ✅ Client Needs Immediate Response:
GET /user/123→ Must return user data now.POST /login→ Must return auth token now.
- ✅ Read Operations (Queries):
- Fetching data from a database.
- RabbitMQ is for events, not queries.
- ✅ Transactional Operations (Within One Service):
POST /ordersthat only involves the Order Service's DB.- No need for async if it's all local.
- ✅ Client Needs Immediate Response:
- When NOT to Use ASYNC?
- ❌ Synchronous Request/Reply (RPC):
- Client sends message → Waits for response message.
- This is "RPC over MQ" and it's slow + complex. Use HTTP/gRPC instead.
- ❌ Real-Time Communication:
- Chat messages, live updates, multiplayer games.
- Use WebSockets/Server-Sent Events instead.
- ❌ Synchronous Request/Reply (RPC):
- RULE OF THUMB:
- Does the client need an answer NOW?
- YES → Use SYNC (HTTP/gRPC)
- NO → Use ASYNC (RabbitMQ)
- Is the operation risky/slow/heavy?
- YES → Use ASYNC (RabbitMQ)
- NO → Either is fine (prefer SYNC for simplicity)
- Does the client need an answer NOW?
- Visualization:
- A decision tree flowchart:
- Start: "Does client need answer NOW?"
- YES → "Use SYNC (HTTP/gRPC)"
- NO → "Is operation risky/slow/heavy?"
- YES → "Use ASYNC (RabbitMQ)"
- NO → "Either (prefer SYNC for simplicity)"
- Start: "Does client need answer NOW?"
- A comparison table:
Criteria SYNC (HTTP) ASYNC (RabbitMQ) Latency Low (< 100ms) High (seconds to minutes) Coupling Tight (caller waits) Loose (fire-and-forget) Resilience Low (cascading failure) High (queue buffers failures) Use Cases Queries, Reads, Auth Events, Notifications, Heavy tasks
- A decision tree flowchart:
- Instructor Script:
- "Finally, let's talk about when to use Async and when not to."
- "[Point to decision tree] Start with this question: Does the client need an answer NOW?"
- "If YES (e.g., 'get me user 123's info'), you must use SYNC. Never use RabbitMQ for queries. It's the wrong tool."
- "If NO (e.g., 'send this email'), ask the next question: Is the operation risky, slow, or heavy?"
- "If YES, you must use ASYNC. Email providers can go down. Don't make your order API wait for that."
- "[Point to comparison table] This table summarizes the trade-offs. SYNC is fast but fragile. ASYNC is resilient but has higher latency."
- "In Assignment 03, you'll use ASYNC for 'UserCreated' notifications. In the real world, 70-80% of your operations will be ASYNC."
Slide 27: Module 3 Summary
- Content:
- MODULE 3 SUMMARY
-
- Sync communication (API Call) is fast, but fragile (tight coupling, cascading failure).
-
- Async communication (Message) is resilient and decoupled.
-
- Production-Ready = Durable (Queue/Exchange) + Persistent (Message) + Safe (Manual ACK + Prefetch) + Error Handling (DLQ).
-
- Producer ->
Exchange(Durable) +Message(Persistent).
- Producer ->
-
- Consumer ->
Queue(Durable) +Binding+basic_consume(auto_ack=False).
- Consumer ->
- Visualization:
- 5 summary bullet points. Item #3 (Production-Ready) is highlighted in red.
- Instructor Script:
- "To summarize. Sync is fast but fragile. Async is resilient. But 'Async' is not automatically 'safe'."
- "'Safe' (Production-Ready) is a 'recipe' with 3 ingredients: Durable/Persistent (so you don't lose data on restart), Safe (so you don't lose data on consumer crash), and Error Handling (so you don't lose data on code error). All the upgraded code today was to serve these 3 goals."
Slide 28: Q&A
- Content:
- Q & A
- Questions & Answers
- Visualization:
- A clean, minimal slide. Just the large letters "Q&A".
- Instructor Script:
- "Thank you. This part was very technical and had many new concepts, so I'm sure there are questions. Please, let's hear them."
Slide 29: Thank You & Next Module
- Content:
- THANK YOU!
- (Your Contact Info: Email, LinkedIn, etc.)
- COMING UP (MODULE 4):
- Module 4: SAGA Pattern
- We know how to send a "safe message." But how do we manage a "transaction" that spans 5 messages? And what do we do when one message fails (NACK/DLQ)?
- Visualization:
- A "teaser" for Module 4.
- A diagram:
[Order] -> (Event) -> [Payment] [Payment] -> (Event) -> [Inventory]- And a red (Failure) arrow going backward:
[Inventory] -> (Compensation Event)
- Instructor Script:
- "Thank you. In Module 3, we learned how to send one message safely and handle its failure with
NACKandDLQ." - "In Module 4, we will use these exact tools to solve our 'Place Order' problem from Slide 5. How do we ensure that Payment and Inventory both succeed, or both fail (roll back)? That is the SAGA Pattern, and it's built directly on the Async foundation we just learned."
- "Thank you. In Module 3, we learned how to send one message safely and handle its failure with
API Gateway with Kong - Slides
Instructor slide content for Unit 2: configuring Kong API Gateway for routing, authentication, and service management
Distributed Transactions & SAGA Pattern - Slides
Instructor slide content for Unit 4: managing distributed transactions across microservices using choreography and orchestration SAGA patterns