home / skills / eyadsibai / ltk / microservices-patterns

This skill helps you design robust microservices architectures by defining boundaries, communication, and resilience patterns for scalable systems.

npx playbooks add skill eyadsibai/ltk --skill microservices-patterns

Review the files below or copy the command above to add this skill to your agents.

Files (1)
SKILL.md
4.3 KB
---
name: microservices-patterns
description: Use when designing microservices architectures, decomposing monoliths, implementing service boundaries, inter-service communication, or asking about "microservices", "service decomposition", "API gateway", "circuit breaker", "distributed systems"
version: 1.0.0
---

# Microservices Patterns

Design microservices architectures with service boundaries, event-driven communication, and resilience patterns.

## Service Decomposition Strategies

### By Business Capability

- Organize services around business functions
- Each service owns its domain
- Example: OrderService, PaymentService, InventoryService

### By Subdomain (DDD)

- Core domain, supporting subdomains
- Bounded contexts map to services
- Clear ownership and responsibility

### Strangler Fig Pattern

- Gradually extract from monolith
- New functionality as microservices
- Proxy routes to old/new systems

## Communication Patterns

### Synchronous (Request/Response)

```python
from tenacity import retry, stop_after_attempt, wait_exponential

class ServiceClient:
    def __init__(self, base_url: str):
        self.base_url = base_url
        self.client = httpx.AsyncClient(timeout=5.0)

    @retry(stop=stop_after_attempt(3), wait=wait_exponential(min=2, max=10))
    async def get(self, path: str, **kwargs):
        response = await self.client.get(f"{self.base_url}{path}", **kwargs)
        response.raise_for_status()
        return response.json()
```

### Asynchronous (Events/Messages)

```python
from aiokafka import AIOKafkaProducer

class EventBus:
    async def publish(self, event: DomainEvent):
        await self.producer.send_and_wait(
            event.event_type,
            value=asdict(event),
            key=event.aggregate_id.encode()
        )
```

## Resilience Patterns

### Circuit Breaker

```python
class CircuitBreaker:
    def __init__(self, failure_threshold=5, recovery_timeout=30):
        self.failure_threshold = failure_threshold
        self.recovery_timeout = recovery_timeout
        self.state = CircuitState.CLOSED

    async def call(self, func, *args, **kwargs):
        if self.state == CircuitState.OPEN:
            if self._should_attempt_reset():
                self.state = CircuitState.HALF_OPEN
            else:
                raise CircuitBreakerOpenError()

        try:
            result = await func(*args, **kwargs)
            self._on_success()
            return result
        except Exception:
            self._on_failure()
            raise
```

### Bulkhead Pattern

- Isolate resources per service
- Limit impact of failures
- Prevent cascade failures

## API Gateway Pattern

```python
class APIGateway:
    @circuit(failure_threshold=5, recovery_timeout=30)
    async def call_service(self, service_url: str, path: str, **kwargs):
        response = await self.http_client.request("GET", f"{service_url}{path}", **kwargs)
        response.raise_for_status()
        return response.json()

    async def aggregate(self, order_id: str) -> dict:
        # Parallel requests to multiple services
        order, payment, inventory = await asyncio.gather(
            self.call_order_service(f"/orders/{order_id}"),
            self.call_payment_service(f"/payments/order/{order_id}"),
            self.call_inventory_service(f"/reservations/order/{order_id}"),
            return_exceptions=True
        )
        return {"order": order, "payment": payment, "inventory": inventory}
```

## Data Management

### Database Per Service

- Each service owns its data
- No shared databases
- Loose coupling

### Saga Pattern for Distributed Transactions

- See saga-orchestration skill for details

## Best Practices

1. **Service Boundaries**: Align with business capabilities
2. **Database Per Service**: No shared databases
3. **API Contracts**: Versioned, backward compatible
4. **Async When Possible**: Events over direct calls
5. **Circuit Breakers**: Fail fast on service failures
6. **Distributed Tracing**: Track requests across services
7. **Health Checks**: Liveness and readiness probes

## Common Pitfalls

- **Distributed Monolith**: Tightly coupled services
- **Chatty Services**: Too many inter-service calls
- **No Circuit Breakers**: Cascade failures
- **Synchronous Everything**: Tight coupling
- **Ignoring Network Failures**: Assuming reliable network

Overview

This skill provides practical patterns and guidance for designing microservices architectures, decomposing monoliths, and implementing resilient inter-service communication. It focuses on service boundaries, communication styles (synchronous and asynchronous), resilience patterns, and operational best practices to avoid common distributed-system pitfalls.

How this skill works

The skill describes decomposition strategies (business capability, DDD subdomains, and the Strangler Fig) and shows code patterns for synchronous clients, event publishing, API gateway aggregation, and resilience primitives like circuit breakers and bulkheads. It explains data ownership (database per service), transactional approaches (sagas), and operational controls such as health checks and distributed tracing. Practical code snippets illustrate retry, async messaging, and circuit-breaker behavior.

When to use it

  • Designing or evaluating a new microservices architecture
  • Decomposing a monolith incrementally using the Strangler Fig
  • Defining service boundaries and database ownership
  • Choosing between synchronous APIs and event-driven messaging
  • Hardening inter-service calls with retries, circuit breakers, and bulkheads

Best practices

  • Align service boundaries with business capabilities or bounded contexts
  • Give each service its own database to avoid tight coupling
  • Favor async events for eventual consistency; use sagas for distributed transactions
  • Version APIs and maintain backward compatibility for smooth evolution
  • Implement circuit breakers, bulkheads, retries, and timeouts to fail fast and isolate faults
  • Add distributed tracing and health probes to observe and operate the system

Example use cases

  • Extracting an OrderService and PaymentService from a monolith using the Strangler Fig pattern
  • Implementing an API gateway that aggregates responses from order, payment, and inventory services
  • Publishing domain events to Kafka for async processing and eventual consistency
  • Adding a circuit breaker around external payment provider calls to avoid cascading failures
  • Designing database-per-service boundaries to prevent cross-service data coupling

FAQ

When should I choose synchronous calls over asynchronous messaging?

Use synchronous request/response for low-latency, strongly consistent operations where immediate results are required. Prefer async events for decoupling, scalability, and eventual consistency when immediate results are not necessary.

How do I avoid a distributed monolith?

Keep services autonomous: own data, minimize synchronous chatty calls, enforce clear contracts, and design teams around service ownership. Use async communication and domain-aligned boundaries to reduce coupling.