Microservices architecture patterns. Use when designing service decomposition, inter-service communication, API gateways, service discovery, event-driven architecture, or distributed systems.
Scanned 9/7/2026
Install to Claude Code
npx -y skills add cohen-liel/hivemind --skill microservices --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Microservices?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/cohen-liel-microservices)More formats (shields.io, HTML) on the badges page.
---
name: microservices
description: Microservices architecture patterns. Use when designing service decomposition, inter-service communication, API gateways, service discovery, event-driven architecture, or distributed systems.
---
# Microservices Architecture Patterns
## Service Structure
```
services/
api-gateway/ # Entry point, routing, auth
user-service/ # User management, auth
product-service/ # Products, catalog, inventory
order-service/ # Orders, checkout flow
notification-service/ # Email, push, SMS (event-driven)
payment-service/ # Stripe, billing
shared/
proto/ # gRPC definitions (if used)
events/ # Event schemas (Pydantic/TypeScript)
libs/ # Shared utilities
docker-compose.yml
```
## API Gateway (FastAPI)
```python
# api-gateway/main.py
import httpx
from fastapi import FastAPI, Request, Depends, HTTPException
from fastapi.middleware.cors import CORSMiddleware
app = FastAPI()
app.add_middleware(CORSMiddleware, allow_origins=["*"], allow_methods=["*"])
SERVICE_URLS = {
"users": "http://user-service:8001",
"products": "http://product-service:8002",
"orders": "http://order-service:8003",
}
@app.api_route("/{service}/{path:path}", methods=["GET", "POST", "PUT", "DELETE", "PATCH"])
async def proxy(service: str, path: str, request: Request, user=Depends(verify_token)):
if service not in SERVICE_URLS:
raise HTTPException(404, "Service not found")
url = f"{SERVICE_URLS[service]}/{path}"
async with httpx.AsyncClient() as client:
response = await client.request(
method=request.method,
url=url,
headers={"X-User-Id": str(user.id), "X-User-Role": user.role},
content=await request.body(),
params=dict(request.query_params),
timeout=30,
)
return Response(content=response.content, status_code=response.status_code,
media_type=response.headers.get("content-type"))
```
## Inter-Service Communication
### Synchronous (HTTP)
```python
# Shared HTTP client with circuit breaker
import httpx
from tenacity import retry, stop_after_attempt, wait_exponential
class ServiceClient:
def __init__(self, base_url: str):
self.client = httpx.AsyncClient(base_url=base_url, timeout=10)
@retry(stop=stop_after_attempt(3), wait=wait_exponential(multiplier=1, min=1, max=10))
async def get(self, path: str, **kwargs):
response = await self.client.get(path, **kwargs)
response.raise_for_status()
return response.json()
# order-service calling user-service
user_client = ServiceClient("http://user-service:8001")
async def get_order_with_user(order_id: str):
order = await db.orders.find_one(order_id)
user = await user_client.get(f"/users/{order['user_id']}") # Retries on failure
return {**order, "user": user}
```
### Asynchronous (Events via Redis/RabbitMQ)
```python
# events/schemas.py
from pydantic import BaseModel
from datetime import datetime
class OrderPlacedEvent(BaseModel):
event_type: str = "order.placed"
order_id: str
user_id: str
amount: float
items: list[dict]
timestamp: datetime = Field(default_factory=datetime.utcnow)
class UserRegisteredEvent(BaseModel):
event_type: str = "user.registered"
user_id: str
email: str
name: str
timestamp: datetime = Field(default_factory=datetime.utcnow)
# Publisher
import aioredis, json
redis = aioredis.from_url(settings.REDIS_URL)
async def publish_event(event: BaseModel):
channel = event.event_type.replace(".", ":")
await redis.publish(channel, event.model_dump_json())
# In order-service after creating order:
await publish_event(OrderPlacedEvent(
order_id=order.id,
user_id=user_id,
amount=total,
items=items,
))
# Subscriber (notification-service)
async def start_consumers():
pubsub = redis.pubsub()
await pubsub.subscribe("order:placed", "user:registered")
async for message in pubsub.listen():
if message["type"] == "message":
channel = message["channel"]
data = json.loads(message["data"])
if channel == "order:placed":
event = OrderPlacedEvent(**data)
await send_order_confirmation_email(event)
elif channel == "user:registered":
event = UserRegisteredEvent(**data)
await send_welcome_email(event)
```
## Service Template (Individual Service)
```python
# user-service/main.py
from fastapi import FastAPI, Header, HTTPException
from contextlib import asynccontextmanager
@asynccontextmanager
async def lifespan(app: FastAPI):
app.state.db = await create_db_pool()
yield
await app.state.db.close()
app = FastAPI(lifespan=lifespan)
# Services trust X-User-Id header from gateway (already authenticated)
def get_current_user_id(x_user_id: str = Header(...)):
return x_user_id
@app.get("/users/me")
async def get_me(user_id: str = Depends(get_current_user_id)):
return await db.get_user(user_id)
@app.get("/users/{user_id}")
async def get_user(user_id: str):
"""Internal endpoint — called by other services."""
user = await db.get_user(user_id)
if not user:
raise HTTPException(404, "User not found")
return user
```
## Docker Compose (Development)
```yaml
# docker-compose.yml
version: '3.9'
services:
api-gateway:
build: ./api-gateway
ports: ["8000:8000"]
environment:
- USER_SERVICE_URL=http://user-service:8001
depends_on: [user-service, product-service]
user-service:
build: ./user-service
environment:
- DATABASE_URL=postgresql://postgres:password@postgres:5432/users
- REDIS_URL=redis://redis:6379
depends_on: [postgres, redis]
product-service:
build: ./product-service
environment:
- DATABASE_URL=postgresql://postgres:password@postgres:5432/products
depends_on: [postgres]
notification-service:
build: ./notification-service
environment:
- REDIS_URL=redis://redis:6379
- RESEND_API_KEY=${RESEND_API_KEY}
depends_on: [redis]
postgres:
image: postgres:16
environment:
POSTGRES_PASSWORD: password
volumes:
- postgres_data:/var/lib/postgresql/data
- ./init.sql:/docker-entrypoint-initdb.d/init.sql
redis:
image: redis:7-alpine
volumes: [redis_data:/data]
volumes:
postgres_data:
redis_data:
```
## Health Checks
```python
@app.get("/health")
async def health():
"""Standard health check endpoint for load balancers."""
checks = {}
try:
await db.execute("SELECT 1")
checks["database"] = "ok"
except Exception:
checks["database"] = "error"
try:
await redis.ping()
checks["redis"] = "ok"
except Exception:
checks["redis"] = "error"
status = "ok" if all(v == "ok" for v in checks.values()) else "degraded"
return {"status": status, "service": "user-service", "checks": checks}
```
## Rules
- Each service owns its database — NEVER share databases between services
- API Gateway handles auth — services trust X-User-Id header (don't re-verify JWT)
- Use events (pub/sub) for cross-service side effects (emails, notifications, analytics)
- Use HTTP for synchronous reads where you need a response immediately
- Each service has its own docker image + migrations — deployable independently
- Retry with exponential backoff for inter-service HTTP calls
- Circuit breaker: after 5 failures, stop calling the service for 30s
- Idempotent event handlers: consuming same event twice should be safe
- One database schema per service (prefix tables: `users_*`, `products_*`)
- Service discovery: use Docker DNS (service name = hostname) in compose
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!