AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL verified MIT Self-run

Microservices

skill-kid-sid-claude-spellbook-microservices · by kid-sid

Use when decomposing a monolith, designing inter-service communication, implementing circuit breakers or sagas, reasoning about data ownership across services, or setting up an API gateway for a distributed system.

No reviews yet
0 installs
38 views
0.0% view→install

Install

$ agentstack add skill-kid-sid-claude-spellbook-microservices

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access Used
  • Filesystem access Used
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-kid-sid-claude-spellbook-microservices)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
3mo ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Microservices? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

Microservices Patterns

Design and implementation patterns for decomposing monoliths and building reliable distributed backend systems.

When to Activate

  • Decomposing a monolith into services or defining service boundaries
  • Choosing between synchronous (REST/gRPC) and asynchronous (messaging) communication
  • Implementing resilience patterns: circuit breaker, retry, bulkhead, timeout
  • Designing data ownership and cross-service transactions (Saga, CQRS)
  • Setting up an API gateway or BFF for client-facing traffic
  • Designing for eventual consistency or event-driven workflows
  • Debugging distributed failures, cascading errors, or data inconsistency

Service Decomposition

Decomposition Strategies

| Strategy | Approach | Best For | |---|---|---| | By domain (DDD) | Align services to bounded contexts | Greenfield, domain-rich systems | | By subdomain | Core / supporting / generic subdomains | Prioritising build-vs-buy | | Strangler fig | Incrementally replace monolith routes | Existing monoliths | | By volatility | Isolate frequently-changing logic | High-churn business rules |

Bounded Context Rules

# BAD: Shared User model across services
OrderService   → reads User.loyaltyPoints
PaymentService → reads User.billingAddress
EmailService   → reads User.email

# GOOD: Each service owns what it needs
OrderService   → owns OrderCustomer { id, name, loyaltyPoints }
PaymentService → owns PaymentProfile { userId, billingAddress, paymentMethods }
EmailService   → owns ContactRecord { userId, email, preferences }

Each service owns its data. No direct cross-service DB queries.

Strangler Fig Migration

1. Route all traffic through a facade (nginx / API gateway)
2. Identify one vertical slice (e.g., /api/payments/*)
3. Implement that slice as a new service
4. Re-route the facade to the new service
5. Delete the monolith code for that slice
6. Repeat — monolith shrinks, services grow

Inter-Service Communication

Sync vs Async Decision

| Factor | Sync (REST / gRPC) | Async (Queue / Events) | |---|---|---| | Latency requirement | Low — caller needs immediate response | Can tolerate delay | | Coupling | Temporal coupling (both must be up) | Decoupled — producer/consumer independent | | Use case | Queries, user-facing reads | Commands, workflows, notifications | | Error handling | Propagates to caller immediately | Dead-letter queue, retry policies | | Throughput | Limited by slowest service | Buffered; consumer scales independently |

Sync: REST

# Python — requests with retry and timeout
import httpx
from tenacity import retry, stop_after_attempt, wait_exponential

@retry(stop=stop_after_attempt(3), wait=wait_exponential(multiplier=1, min=1, max=10))
def get_user(user_id: str) -> dict:
    response = httpx.get(
        f"http://user-service/users/{user_id}",
        timeout=2.0,  # always set a timeout
    )
    response.raise_for_status()
    return response.json()["data"]
// TypeScript — fetch with timeout and retry
async function getUser(userId: string): Promise {
  const controller = new AbortController();
  const timeout = setTimeout(() => controller.abort(), 2000);
  try {
    const res = await fetch(`http://user-service/users/${userId}`, {
      signal: controller.signal,
    });
    if (!res.ok) throw new Error(`upstream error: ${res.status}`);
    return (await res.json()).data;
  } finally {
    clearTimeout(timeout);
  }
}
// Go — http client with timeout
func (c *UserClient) GetUser(ctx context.Context, userID string) (*User, error) {
    ctx, cancel := context.WithTimeout(ctx, 2*time.Second)
    defer cancel()

    req, _ := http.NewRequestWithContext(ctx, http.MethodGet,
        fmt.Sprintf("http://user-service/users/%s", userID), nil)
    resp, err := c.http.Do(req)
    if err != nil {
        return nil, fmt.Errorf("user-service: %w", err)
    }
    defer resp.Body.Close()
    // decode...
}

Sync: gRPC (preferred for internal service-to-service)

// order.proto
service OrderService {
  rpc GetOrder (GetOrderRequest) returns (Order);
  rpc CreateOrder (CreateOrderRequest) returns (Order);
  rpc ListOrders (ListOrdersRequest) returns (stream Order);  // server streaming
}

message GetOrderRequest { string order_id = 1; }
message Order {
  string id = 1;
  string customer_id = 2;
  OrderStatus status = 3;
  repeated OrderItem items = 4;
}

Async: Message Broker

# Python — publishing an event (Kafka)
from confluent_kafka import Producer
import json

producer = Producer({"bootstrap.servers": "kafka:9092"})

def publish_order_placed(order: Order):
    event = {
        "event_type": "order.placed",
        "order_id": order.id,
        "customer_id": order.customer_id,
        "total": str(order.total),
        "occurred_at": order.created_at.isoformat(),
    }
    producer.produce(
        topic="orders",
        key=order.id,
        value=json.dumps(event).encode(),
    )
    producer.flush()
// TypeScript — consuming events (Kafka / KafkaJS)
const consumer = kafka.consumer({ groupId: "notification-service" });
await consumer.subscribe({ topic: "orders", fromBeginning: false });
await consumer.run({
  eachMessage: async ({ message }) => {
    const event = JSON.parse(message.value!.toString());
    if (event.event_type === "order.placed") {
      await notifyCustomer(event.customer_id, event.order_id);
    }
  },
});

Resilience Patterns

Circuit Breaker

# Python — using pybreaker
import pybreaker

breaker = pybreaker.CircuitBreaker(fail_max=5, reset_timeout=30)

@breaker
def call_inventory_service(product_id: str) -> int:
    return inventory_client.get_stock(product_id)

# States: CLOSED (normal) → OPEN (failing, fast-fail) → HALF-OPEN (probing)
// Go — using gobreaker
import "github.com/sony/gobreaker"

cb := gobreaker.NewCircuitBreaker(gobreaker.Settings{
    Name:        "inventory-service",
    MaxRequests: 3,                // requests allowed in half-open
    Interval:    10 * time.Second, // rolling window
    Timeout:     30 * time.Second, // how long to stay OPEN
    ReadyToTrip: func(counts gobreaker.Counts) bool {
        return counts.ConsecutiveFailures > 5
    },
})

stock, err := cb.Execute(func() (interface{}, error) {
    return inventoryClient.GetStock(ctx, productID)
})

Bulkhead

# Isolate thread pools per downstream dependency
from concurrent.futures import ThreadPoolExecutor

_inventory_pool = ThreadPoolExecutor(max_workers=10)  # capped per service
_payment_pool   = ThreadPoolExecutor(max_workers=5)

def get_stock(product_id: str):
    future = _inventory_pool.submit(inventory_client.get_stock, product_id)
    return future.result(timeout=2)

Retry and Backoff

# GOOD: exponential backoff with jitter
attempt 1: wait 1s ± 0.5s
attempt 2: wait 2s ± 1s
attempt 3: wait 4s ± 2s
→ stop after 3 attempts, raise to caller

# BAD: retry storm
for i in range(10):
    try: call_service()
    except: continue  # hammers a degraded service

Data Management

Per-Service Database (Mandatory)

# BAD: shared database
OrderService   → SELECT * FROM payments.transactions WHERE order_id = ?
PaymentService → SELECT * FROM orders.orders WHERE user_id = ?

# GOOD: service-owned databases, expose data via API or events
OrderService   → owns orders_db (Postgres)
PaymentService → owns payments_db (Postgres)
InventoryService → owns inventory_db (Redis + Postgres)

Saga Pattern (Distributed Transactions)

Two flavours:

| Type | Mechanism | Use When | |---|---|---| | Choreography | Each service emits events that trigger the next | Simple flows, low coupling | | Orchestration | Central saga orchestrator drives the steps | Complex flows, explicit rollback |

# Choreography saga — order placement
# 1. OrderService publishes order.created
# 2. PaymentService listens → charges card → publishes payment.succeeded or payment.failed
# 3. InventoryService listens to payment.succeeded → reserves stock → publishes stock.reserved
# 4. OrderService listens to stock.reserved → marks order CONFIRMED
# 5. On any failure: compensating events roll back upstream steps

# Compensating transaction example
def on_payment_failed(event):
    order_service.cancel_order(event["order_id"])   # compensation
    notification_service.notify_customer(event["customer_id"], "payment_failed")

CQRS (Command Query Responsibility Segregation)

Write path:  POST /orders        → OrderCommandHandler → orders_db (normalized)
                                 → publishes order.placed event

Read path:   GET /orders/:id     → OrderQueryHandler   → orders_read_db (denormalized view)
             GET /orders?user=X  → OrderQueryHandler   → orders_read_db (pre-joined)

Read model updated by: consuming order.placed / order.updated events

Use CQRS when read and write models have fundamentally different shapes or scale requirements.

API Gateway and BFF

API Gateway Responsibilities

Client → API Gateway → [UserService, OrderService, ProductService]

Gateway handles:
  - Authentication (JWT verification)
  - Rate limiting per client / API key
  - Request routing / URL rewriting
  - SSL termination
  - Logging and distributed trace injection (X-Request-ID, traceparent)
  - Response aggregation (optional)

Backend for Frontend (BFF)

Mobile App   → Mobile BFF   → [fine-grained internal APIs]
Web App      → Web BFF      → [fine-grained internal APIs]
Partner API  → Partner BFF  → [fine-grained internal APIs]

# Each BFF is thin: aggregate, reshape, and auth-scope data for its client
# BAD: one general-purpose gateway trying to serve all clients equally

Service Discovery

| Method | How | Example | |---|---|---| | Client-side | Client queries registry, picks instance | Netflix Eureka, Consul | | Server-side | Load balancer queries registry | AWS ALB, Kubernetes Service | | DNS-based | Use DNS SRV records | Kubernetes (default), Consul DNS | | Environment | Inject service URLs at deploy time | Docker Compose, Helm values |

Kubernetes DNS-based (simplest):

# payment-service resolves to:
# http://payment-service.payments-ns.svc.cluster.local:8080
# within the same namespace: http://payment-service:8080

Observability in Microservices

Distributed tracing is non-negotiable:

# Propagate trace context across services (OpenTelemetry)
from opentelemetry import trace
from opentelemetry.propagate import inject, extract

tracer = trace.get_tracer("order-service")

def place_order(order_data: dict, headers: dict):
    ctx = extract(headers)  # pull trace context from incoming request
    with tracer.start_as_current_span("place_order", context=ctx) as span:
        span.set_attribute("order.customer_id", order_data["customer_id"])
        outbound_headers = {}
        inject(outbound_headers)  # inject into outbound calls
        payment_client.charge(order_data, headers=outbound_headers)

> See also: observability

Red Flags

  • Services sharing a database — two services reading and writing the same table are coupled at the schema level; a migration needed by one service blocks or breaks the other, defeating the purpose of independent deployment
  • Synchronous HTTP chain more than 2 hops deep — a request that fans out through 5 services compounds each service's p99 latency multiplicatively; use async messaging for workflows that do not need an immediate response
  • No timeout on inter-service HTTP calls — an unresponsive downstream service holds goroutines/threads until the connection pool is exhausted, cascading the failure to every caller upstream
  • Saga with no compensating transaction defined — a choreography saga that publishes order.created without a cancel_order compensation path leaves partial state (charged payment, no order) when any downstream step fails
  • Consumer reading directly from the producer's database — bypassing the API to read raw DB rows creates an undocumented cross-service coupling; any schema change in the producer silently breaks the consumer
  • gRPC without deadline propagation — calling a downstream gRPC service without passing the parent context deadline means the downstream call ignores the caller's timeout and can outlive the client connection
  • Circuit breaker with the same threshold for all dependencies — a cache (millisecond latency, 99.99% uptime) and a fraud-check API (200ms, 99.9% uptime) need different fail_max and reset_timeout values; one-size config causes false trips on critical paths
  • Event consumer processing messages synchronously within eachMessage — blocking the consumer callback blocks partition consumption; use async handlers and commit offsets only after successful processing to avoid message loss

Checklist

  • [ ] Each service owns its own database — no shared tables or direct cross-DB queries
  • [ ] Service boundaries align to domain bounded contexts, not technical layers
  • [ ] All synchronous calls have explicit timeouts and retry with exponential backoff
  • [ ] Circuit breaker configured for every downstream dependency
  • [ ] Async event schemas are versioned; consumers tolerate unknown fields
  • [ ] Saga compensating transactions defined for every distributed workflow
  • [ ] API gateway handles auth, rate limiting, and trace injection centrally
  • [ ] Distributed tracing propagated across all service calls (W3C traceparent)
  • [ ] Dead-letter queues configured for all async consumers
  • [ ] Health check endpoints (/healthz, /readyz) implemented in every service
  • [ ] Services degrade gracefully when a dependency is unavailable (fallback/cache)
  • [ ] Data contracts (API schemas, event schemas) reviewed before breaking changes

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.