Loading...

Kafka Crash Course: Learn with a Parent's Return to Office Mandate Problem

Kafka Crash Course: Learn with a Parent's Return to Office Mandate Problem

The Problem: Companies are mandating return-to-office. Parents now face a coordination challenge:

  • School bus drops kids at 3:15 PM at the community bus stop
  • Parents need to be there, but meetings run over
  • Group chats don’t work - messages get buried, no confirmation

Real scenario:

3:10 PM - Sarah's meeting runs over
3:11 PM - Posts in group chat: "Can someone watch Jake?"
3:15 PM - Bus arrives, no response yet

Neighbors want to help. They just need a reliable system.

Why Kafka Fits This Problem

Before: Tightly Coupled Services

Parent App → Notification Service → Database → Neighbor App

Problems:

  • Notification service crashes = everything stops
  • Parent waits for entire chain to respond
  • Neighbor offline = message lost forever

With Kafka: Decoupled

Parent App → Kafka ← Neighbor Apps

Benefits:

  • Parent sends alert, doesn’t wait
  • Message stored safely in Kafka
  • Neighbors read when ready (even if offline before)
  • Multiple neighbors can all see it
  • Add new features without breaking existing ones

Think of Kafka as a bulletin board. Pin a message, walk away. Everyone sees it. First person to help responds.

Kafka Architecture Diagram


Let’s Build It

What we need:

  • Docker (to run Kafka)
  • Python (to write producer/consumer)

Virtual Environment Setup

  1. Create the project folder and navigate to it:
mkdir bus-stop-kafka
cd bus-stop-kafka
  1. Create a virtual environment:
python3 -m venv venv
  1. Activate the virtual environment:
source venv/bin/activate
  1. Install librdkafka (required C library for macOS):
brew install librdkafka
  1. Upgrade pip and install dependencies:
pip install --upgrade pip
pip install confluent-kafka

The virtual environment is now set up and isolated from your system Python installation.

Start Kafka

Create docker-compose.yml:

version: '3.8'
services:
  kafka:
    image: confluentinc/cp-kafka:7.8.3
    container_name: kafka
    ports:
      - "9092:9092"
    environment:
      KAFKA_KRAFT_MODE: "true"
      CLUSTER_ID: "bus-stop-demo"
      KAFKA_NODE_ID: 1
      KAFKA_PROCESS_ROLES: "broker,controller"
      KAFKA_LISTENERS: "PLAINTEXT://0.0.0.0:9092,CONTROLLER://0.0.0.0:9093"
      KAFKA_ADVERTISED_LISTENERS: "PLAINTEXT://localhost:9092"
      KAFKA_CONTROLLER_LISTENER_NAMES: "CONTROLLER"
      KAFKA_CONTROLLER_QUORUM_VOTERS: "1@kafka:9093"
      KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
      KAFKA_LOG_DIRS: "/var/lib/kafka/data"
    volumes:
      - kafka-data:/var/lib/kafka/data

volumes:
  kafka-data:

Start it:

docker-compose up -d
sleep 30  # Wait for Kafka to start

Producer (Sarah Sends Alert)

Create producer.py:

from confluent_kafka import Producer
import json

# Connect to Kafka
producer = Producer({'bootstrap.servers': 'localhost:9092'})

# Create alert message
alert = {
    'parent_name': 'Sarah',
    'child_name': 'Jake',
    'location': 'Oak Street Bus Stop',
    'message': 'Meeting ran over, will be 10 mins late'
}

# Send to Kafka topic
producer.produce(
    topic='bus-stop-alerts',           # Topic name
    value=json.dumps(alert).encode()   # Convert to bytes
)

producer.flush()  # Ensure it's sent

print(f"✅ Alert sent: {alert['parent_name']} needs help")

Run it (ensure your virtual environment is activated):

python producer.py
# Output: ✅ Alert sent: Sarah needs help

What happened:

  1. Connected to Kafka at localhost:9092
  2. Created JSON message with alert details
  3. Sent to topic called bus-stop-alerts
  4. Kafka stored it

Consumer (Mike Receives Alert)

Create consumer.py:

from confluent_kafka import Consumer
import json

# Connect to Kafka
consumer = Consumer({
    'bootstrap.servers': 'localhost:9092',
    'group.id': 'neighbors',              # Consumer group
    'auto.offset.reset': 'earliest'       # Read from beginning
})

consumer.subscribe(['bus-stop-alerts'])
print("🔔 Listening for alerts...\n")

try:
    while True:
        msg = consumer.poll(1.0)  # Check every second
        
        if msg is None:
            continue
        
        if msg.error():
            print(f"Error: {msg.error()}")
            continue
        
        # Got a message!
        alert = json.loads(msg.value().decode())
        
        print(f"🚨 {alert['parent_name']} needs help!")
        print(f"   Child: {alert['child_name']}")
        print(f"   Location: {alert['location']}")
        print(f"   Message: {alert['message']}\n")

except KeyboardInterrupt:
    print("Stopped")
finally:
    consumer.close()

Run it (ensure your virtual environment is activated):

python consumer.py

Output:

🔔 Listening for alerts...

🚨 Sarah needs help!
   Child: Jake
   Location: Oak Street Bus Stop
   Message: Meeting ran over, will be 10 mins late

What happened:

  1. Consumer connected to Kafka
  2. Subscribed to bus-stop-alerts topic
  3. Read the message Sarah sent
  4. Keeps running, waiting for more

Understanding Kafka Concepts

Topics

  • Like folders for messages
  • We used: bus-stop-alerts
  • Organizes different types of messages

Producers

  • Send messages to topics
  • Don’t wait for consumers
  • Don’t know who will read it

Consumers

  • Read messages from topics
  • Can start from beginning or latest
  • Keep polling for new messages

Consumer Groups

  • Multiple consumers with same group.id
  • Kafka distributes messages among them
  • Load balancing automatically

Try This: Messages Persist

Shows: Messages don’t disappear

  1. Start consumer, then stop it (Ctrl+C)
  2. Send 3 alerts:

    python producer.py
    python producer.py
    python producer.py
    
  3. Start consumer again

Result: Consumer shows all 3 alerts!

Why this matters: If Mike’s phone was off when Sarah sent alert, he still sees it when phone turns back on.

Important: Consumer Offset Tracking

Question: “If I sent 1 alert earlier and 3 alerts now, why don’t I see all 4 alerts?”

Answer: Kafka tracks where each consumer group left off reading using offsets.

Here’s what happens:

  1. First run: producer.py sends alert #1
  2. First run: consumer.py reads alert #1, Kafka marks “neighbors group read up to offset 0”
  3. Second run: producer.py sends alerts #2, #3, #4
  4. Second run: consumer.py only shows #2, #3, #4 (skips #1 because it was already read)

This is a feature, not a bug! Imagine if neighbors saw every alert from the past month every time they checked.

To see ALL messages from the beginning:

Option 1 - Change consumer group name (line 197 in consumer.py):

'group.id': 'neighbors-v2',  # New group = starts fresh

Option 2 - Delete the consumer group offset tracking:

docker exec -it kafka kafka-consumer-groups \
  --bootstrap-server localhost:9092 \
  --delete --group neighbors

Try This: Multiple Neighbors

Shows: Multiple consumers share work

  1. Open 3 terminals
  2. Run python consumer.py in each (with venv activated)
  3. Send alerts from 4th terminal

Result: Each consumer gets different messages (load balancing)

Why this matters: Multiple neighbors at bus stop, all see alerts, first one responds.

Important: Partitions Enable Load Balancing

Question: “All messages go to one consumer. Is load balancing actually working?”

Answer: With the default setup (1 partition), load balancing cannot work. Here’s why:

The Partition Rule:

Maximum parallel consumers = Number of partitions

By default, bus-stop-alerts has 1 partition, so:

  • Consumer #1 gets partition 0 (receives all messages)
  • Consumer #2 gets nothing (no partitions left)
  • Consumer #3 gets nothing

To see actual load balancing:

  1. Delete the topic:
    docker exec -it kafka kafka-topics \
      --bootstrap-server localhost:9092 \
      --delete --topic bus-stop-alerts
    
  2. Recreate with 3 partitions:
    docker exec -it kafka kafka-topics \
      --bootstrap-server localhost:9092 \
      --create --topic bus-stop-alerts \
      --partitions 3 \
      --replication-factor 1
    
  3. Run 3 consumers in separate terminals:
    python consumer.py  # Terminal 1
    python consumer.py  # Terminal 2
    python consumer.py  # Terminal 3
    
  4. Send multiple alerts:
    python producer.py  # Run this 6+ times
    

Now you’ll see: Messages distributed across all 3 consumers!

Key insight: More partitions = more parallelism. This is how Kafka scales to handle massive throughput.


The Power of Kafka

Real-World Flow

Sarah (3:10 PM)
  ↓ sends alert
Kafka (stores it)
  ↓ notifies consumers
Mike (3:11 PM) - sees alert
Lisa (3:11 PM) - sees alert
David (3:12 PM) - phone was locked, sees it now
  ↓
Mike responds "I'll watch Jake"
  ↓ sends confirmation through Kafka
Sarah (3:12 PM) - sees confirmation

Why This Architecture Works

Decoupling:

  • Services don’t talk directly
  • Add/remove services without breaking others

Persistence:

  • Messages stored on disk
  • Survive crashes and restarts

Scalability:

  • Add more consumers = faster processing
  • Add more producers = handle more load

Reliability:

  • One service down? Others keep working
  • Messages don’t get lost

Real-World Use Cases

Same pattern, different problems:

E-commerce:

  • Order placed → Kafka
  • Payment service charges card
  • Inventory service updates stock
  • Email service sends confirmation

Uber:

  • Ride requested → Kafka
  • Driver matching finds nearby driver
  • Pricing calculates fare
  • Notifications alert driver

Your bus stop:

  • Alert sent → Kafka
  • Notification service alerts neighbors
  • Database logs the event
  • Analytics tracks usage

All use the same Kafka pattern you just learned.


Common Questions

“Why not just use a database?”

  • Database: Consumer constantly polls “any new data?”
  • Kafka: Consumer waits, Kafka notifies when ready
  • Result: Real-time, less load

“Why not just use REST API?”

  • REST: Consumer must be online NOW
  • Kafka: Consumer reads when ready
  • Result: More reliable, works offline

“When should I use Kafka?”

  • ✅ High message volume
  • ✅ Multiple systems need same data
  • ✅ Can’t lose messages
  • ✅ Need message history

What You Built

bus-stop-kafka/
├── docker-compose.yml  # Kafka setup
├── producer.py         # Send alerts
├── consumer.py         # Receive alerts
├── venv/               # Virtual environment
├── .gitignore          # Git ignore file
└── README.md           # Project documentation

Summary

You learned:

  • What Kafka is (message broker)
  • Why it’s useful (decoupling, persistence)
  • How to produce messages
  • How to consume messages
  • Consumer groups concept

You built:

  • Working producer that sends alerts
  • Working consumer that receives alerts
  • Everything runs locally with Docker

You can now:

  • Explain Kafka to anyone
  • Build event-driven systems
  • Apply this to other problems

Resources

📦 Code: github.com/sprider/bus-stop-kafka
📚 Learn More: Kafka Docs
🎥 Watch: Nana’s Kafka Video

Published on:

Learn more
Home | Joseph Velliah
Home | Joseph Velliah

Fulfilling God’s purpose for my life

Share post:

Related posts

Vasanam Studio: How I Built a Bible Verse Video Generator for My Church as a Hobby Project

Every morning at 5 AM, the women of my church gather for prayer. At the end of the session, our pastor’s wife shares a Bible verse and sends a...

2 months ago

The demo worked. That was the problem.

Over a weekend I built a small Kubernetes demo to play with zero trust. Three little services calling each other in a chain, a login page in f...

2 months ago

Notes from building an agent on AgentCore end to end

I wanted a reason to use AgentCore end to end. Runtime, memory, guardrails, identity, the whole thing. A Bible Q&A agent felt like a good ...

4 months ago

Building a Rust gRPC AI Security Gateway for LLM Traffic

I wanted a small, honest implementation of the GenAI governance shape in code: a component on every LLM call that applies policy first, option...

4 months ago

Claude Code Security: The Smart Way to Integrate AI

Anthropic just dropped Claude Code Security, and if you’re anywhere near AppSec or DevSecOps, you’ve probably already seen the debate lighting...

5 months ago

How I Built a Semantic Cache Using Only AWS Services

LLM calls are expensive and slow, but here’s the thing - users ask the same questions in different ways all the time. “What’s your refund poli...

6 months ago

How to Build Better AI Agent Tools: Cut Costs by 70% (MCP Server Case Study)

Building tools for AI agents isn’t the same as building regular APIs. This guide shows you how to design tools that reduce token costs by 60-7...

6 months ago

Building a DevSecOps Pipeline on AWS (And You Can Too)

I have been working with CI/CD pipelines for a while now, and honestly, most of them just focus on getting code deployed fast. But what about ...

7 months ago

AWS DevOps Agent: AI-Powered Incident Investigation in Seconds

Stop spending 30 minutes investigating incidents. Let AI do it in seconds. Here is a hands-on demo you can practice in 15 minutes. The Proble...

8 months ago

DynamoDB Just Made Your Life Easier: Multi-Attribute Composite Keys Explained

AWS just dropped a feature on November 19, 2025 that is going to save you from one of DynamoDB’s most annoying workarounds: multi-attribute co...

8 months ago

Newsletter

Get the latest Dynamics 365 and Power Platform content in your inbox

A curated digest of community blogs, product news, videos, and podcasts — delivered without the noise.

Weekly updates Unsubscribe anytime Fresh community picks
We use your email only for the newsletter and you can unsubscribe at any time.
By subscribing, you agree to the privacy policy.