Contents

Chapter 1

Microservices Patterns Guide

A reference for the architectural patterns used in this kit and when to

apply them in production.


1. API Gateway

What: A single entry point that routes requests to downstream services

and handles cross-cutting concerns (auth, rate limiting, logging).

When to use: Always. Even with two services, a gateway simplifies

client integration and centralises security enforcement.

Client β†’ API Gateway β†’ User Service
                     β†’ Order Service

Trade-offs:

  • Pro: Single TLS termination point, centralised auth
  • Con: Single point of failure (mitigate with replicas and health checks)

2. Database per Service

What: Each microservice owns its data store. Services never access

another service's database directly.

When to use: Default choice. Sharing a database couples services at

the schema level, defeating the purpose of microservices.

Implementation:

python
# user-service owns its own SQLite / Postgres
DATABASE_URL=sqlite:///./users.db

# order-service has its own store
DATABASE_URL=sqlite:///./orders.db

To query data owned by another service, use the service client (HTTP)

or listen for domain events.


3. Domain Events (Event-Driven Communication)

What: Services communicate by publishing and subscribing to events

rather than making synchronous calls.

When to use: When a state change in one service should trigger

behaviour in another without tight coupling.

Order Service  ──publishes──▢  "order.created"
                                    β”‚
User Service  ◀──subscribesβ”€β”€β”€β”€β”€β”€β”€β”€β”˜
  (sends confirmation email)

Transport options (swap the EventBus implementation):

TransportLatencyDurabilityComplexity
In-process~0 msNoneTrivial
Redis Streams~1 msOptionalLow
RabbitMQ~2 msYesMedium
Apache Kafka~5 msYesHigh

4. Circuit Breaker

What: Wraps inter-service HTTP calls. After N consecutive failures,

the circuit "opens" and immediately rejects requests for a recovery

period, preventing cascading failures.

States:

  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     N failures     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
  β”‚  CLOSED  β”‚ ─────────────────▢ β”‚   OPEN   β”‚
  β”‚ (normal) β”‚                    β”‚ (reject) β”‚
  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                    β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜
       β–²                               β”‚ recovery timeout
       β”‚         1 success             β”‚
       └──────────────────── β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”
                             β”‚  HALF-OPEN     β”‚
                             β”‚ (probe 1 req)  β”‚
                             β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Configuration (in ServiceClient):

python
client = ServiceClient(
    base_url="http://user-service:8001",
    circuit_failure_threshold=5,   # open after 5 failures
    circuit_recovery_timeout=30.0, # try again after 30s
)

5. Correlation IDs (Distributed Tracing)

What: A unique ID assigned to each external request, propagated

through all inter-service calls via the x-correlation-id header.

Why: In production, a single user click can trigger requests across

5+ services. Without a correlation ID, piecing together the log trail

is impossible.

[a1b2c3d4] POST /api/orders          ← gateway
[a1b2c3d4] GET /users/usr_abc123     ← order-service β†’ user-service
[a1b2c3d4] PUBLISH order.created     ← order-service

Implementation: The CorrelationMiddleware in shared/tracing.py

handles ID generation and propagation automatically.


6. Health Checks

What: Each service exposes a /health endpoint. The gateway

aggregates them into a composite health report.

Kubernetes-style probes:

ProbePurposeEndpoint
Liveness"Is the process alive?"/health
Readiness"Can it serve traffic?"/ready
Startup"Has it finished booting?"/health

Production config (in docker-compose.prod.yml):

yaml
healthcheck:
  test: ["CMD", "curl", "-f", "http://localhost:8001/health"]
  interval: 30s
  timeout: 5s
  retries: 3

7. Retry with Exponential Back-Off

What: On transient failures (network blips, 503s), retry the

request after an exponentially increasing delay.

Attempt 1 β†’ fail β†’ wait 0.5s
Attempt 2 β†’ fail β†’ wait 1.0s
Attempt 3 β†’ fail β†’ give up (or open circuit breaker)

Why: Most transient errors resolve within seconds. Retrying

immediately causes thundering herd problems; back-off spreads the load.


8. Strangler Fig Migration

What: When migrating from a monolith, route traffic through the

gateway. Gradually replace monolith endpoints with microservices.

Gateway
  β”œβ”€β”€ /api/users   β†’ NEW User Service
  β”œβ”€β”€ /api/orders  β†’ NEW Order Service
  └── /api/legacy  β†’ OLD Monolith (shrinking)

Steps:

1. Deploy the gateway in front of the monolith.

2. Extract one bounded context at a time.

3. Route new traffic to the microservice; keep the monolith as fallback.

4. Remove the monolith route once fully migrated.


Quick-Reference: When to Split a Service

SignalAction
Two teams own the same codebaseSplit
Module has independent deploy cycleSplit
Feature requires a different DBSplit
Two modules share the same tableKeep together
Feature is < 200 lines of codeKeep together

*By Datanest Digital β€” Microservices Patterns Guide*

Chapter 2
πŸ”’ Available in full product

Microservices Patterns Guide

You’ve reached the end of the free preview

Get the full Python Microservices Kit and unlock everything.

All Chapters

Get the complete guide with every chapter unlocked, including code samples, diagrams, and best practices.

Full Tool Suite

Access all interactive tools with complete data, all workload profiles, and the full scenario library.

Source Files

Downloadable source code, configuration files, and working examples from every chapter.

Lifetime Updates

Free updates for life. Every new chapter, tool, and improvement included.

Buy Now — $49 →
πŸ“¦ Free sample included — download another copy or visit the store for the full product.
Python Microservices Kit v1.0.0 β€” Free Preview