🍽️ Dining Philosophers

A problem by Edsger Dijkstra (1965)

→ Dining Philosophers → Microservices Architecture → Docker Compose

🍽️ Dining Philosophers Problem

Setup:

  • 5 philosophers seated at a round table
  • Between each pair sits a fork
  • Philosophers alternate between thinking and eating
  • To eat, each philosopher must pick up two forks

The Problem (read wiki!)

If everyone picks up their left fork first:

  • Each is holding one fork
  • None can get the second fork
  • Everyone waits forever → Deadlock

Other failures:

  • Livelock → everyone keeps putting down & retrying in sync
  • Starvation → some philosophers never eat

🎭 Let's Act It Out!

  • 5 students (the philosophers)
  • 5 forks (actual forks!)
  • 5 plates (to represent eating)
  • Arrange chairs in a circle
  • Place one fork between each pair of students

🎬 Activity: Round 1 - Create Deadlock

Rules:

  1. Everyone sits at the table
  2. On "GO", everyone picks up the fork to their left
  3. Wait 3 seconds
  4. Try to pick up the fork to your right

What happens?

  • Everyone holds one fork
  • No one can get the second fork
  • DEADLOCK! 🔒

🎬 Activity: Round 2 - Synchronized Retry

Rules:

  1. Everyone picks up their left fork
  2. If you can't get the right fork after 2 seconds, put down the left
  3. Wait 1 second, then try again
  4. Repeat

What happens?

  • Everyone puts down and picks up in sync
  • Pattern repeats forever
  • LIVELOCK! (everyone busy, nothing accomplished) 🔄

🎬 Activity: Round 3 - Resource Hierarchy

Rules:

  1. Number the forks 1, 2, 3, 4, 5
  2. Always pick up the lower-numbered fork first
  3. Example: Between forks 2 and 3, grab fork 2 first

What happens?

  • One person will be waiting for the "lower" fork
  • No circular wait = No deadlock! ✔️
  • Eventually everyone eats

🎬 Activity: Round 4 - The Waiter

Rules:

  1. Choose one student as the Waiter (stands in center)
  2. Philosophers must ask permission before picking up forks
  3. Waiter only allows 4 philosophers to attempt eating at once

What happens?

  • The 5th philosopher waits
  • The other 4 can acquire forks without conflict
  • Controlled access prevents deadlock ✔️

🎬 Activity: Round 5 - Random Backoff

Rules:

  1. Pick up left fork
  2. If right fork unavailable, put down left fork
  3. Wait a random time (1–5 seconds)
  4. Try again

What happens?

  • Students retry at different intervals
  • Eventually, timing mismatches allow progress
  • Randomization breaks synchronization ✔️

🧠 The resource problem in CS

Abstract problem of resource contention:

  • Competing for shared resources
  • Incorrect ordering - system freeze
  • Poor coordination - low throughput
  • Lack of orchestration - chaos

Similar issues arise in:

  • APIs all waiting on DB connections
  • Microservices waiting on others
  • Containers fighting for ports/volumes
  • Build pipelines mutually blocking

🍽️️ Solutions (Classic)

... as we saw

✔ Resource Hierarchy

Pick forks in a consistent order.

✔ Waiter / Arbiter

A controller grants permission to eat.

✔ Limit Concurrency

Allow only N-1 philosophers to eat simultaneously.

✔ Randomized Backoff

Avoid synchronized retry patterns.

Microservices Architecture Challenges

  • Multiple services need shared resources
  • Services depend on each other
  • Services may start/stop independently
  • Scale dynamically
  • Failures in one service affect others
    • Lack of a single ACID Database

Database per Service Pattern

🔄 Saga Pattern Overview

Failure Management Pattern for Microservices

Distributed transactions across multiple services:

  • Each service performs a local transaction
  • If one fails, compensating transactions undo previous steps
  • No global lock - eventual consistency

Saga Pattern

Two coordination styles:

  1. Choreography >> services listen & react to events
  2. Orchestration >> a central coordinator directs the flow

Saga Pattern Challenges

  • Managing partial failures
  • Designing effective compensations
  • Ensuring idempotency of operations
  • Handling eventual consistency
  • Monitoring & debugging distributed flows

microservices.io
saga-pattern-azure
saga pattern-aws

🍽️ Saga Pattern = Smart Waiter

Like the Dining Philosophers waiter solution:

Dining Philosophers Saga Pattern
Waiter coordinates eating Orchestrator coordinates transactions
Philosopher releases forks if can't eat Service rolls back on failure
Prevent deadlock via sequencing Prevent inconsistency via compensations
One philosopher at a time One transaction step at a time

Key insight: Both prevent system-wide failure through controlled coordination.

🐳 Saga in Docker Architecture

Example: User signs up → multi-service flow

  1. auth-service creates user account
  2. email-service sends welcome email
  3. billing-service sets up payment

If billing fails:

  • Billing triggers compensating transaction
  • Email service marks account as incomplete
  • Auth service flags user for manual review

Docker Compose + event bus (e.g., Redis/RabbitMQ) can implement this!

Back to Dining Philosophers

Your React + Express apps face the similar problems:

  • Services need ports
  • Services depend on each other
  • They share volumes and networks
  • They can deadlock at startup
  • They can starve one another (e.g., DB not ready)

Docker Compose = The Waiter

Just like the waiter solution:

Docker Compose ensures:

  • Proper startup order (depends_on)
  • Stable ports
  • Managed networks
  • Shared volumes
  • Predictable service orchestration

Compose is your arbiter, preventing resource chaos.

🧱 Services = Philosophers

🥢 Ports/Volumes = Forks

Dining Philosophers Docker System
Philosopher Container/Service
Fork Port / Volume / Network
Deadlock Port Conflict / Startup Hang
Waiter docker-compose
Sequencing forks depends_on

📦 Your Architecture

Services:

  • frontend (React + Vite)
  • backend (Express.js)
  • db (optional: Postgres)

They live in separate folders but start as one system.

🐳 Example: docker-compose.yml

services:
  backend:
    build: ./api
    ports:
      - "3000:3000"
    depends_on:
      - db

  frontend:
    build: ./client
    ports:
      - "5173:5173"
    depends_on:
      - backend

  db:
    image: postgres:16
    environment:
      POSTGRES_PASSWORD: secret

📐 Compose view

  • backend waits for db
  • frontend waits for backend
  • Compose acts as waiter :- preventing deadlock
  • Ports are forks → only one service binds each!

🧭 Summary

Dining Philosophers teaches
→ resource contention & orchestration.

Docker Compose solves
→ real-world resource contention in your dev architecture.

  • By managing dependencies, ports, and volumes,
  • It acts as the waiter ensuring smooth operation.

Next:
Build your actual Compose setup for the project!

Dining Philosophers is a pretty classic concurrency problem.