home / skills / aj-geddes / useful-ai-prompts / microservices-architecture

microservices-architecture skill

/skills/microservices-architecture

This skill helps you design and implement scalable microservices architectures with clear boundaries, robust communication, and reliable deployment patterns.

npx playbooks add skill aj-geddes/useful-ai-prompts --skill microservices-architecture

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

Files (1)
SKILL.md
17.0 KB
---
name: microservices-architecture
description: Design and implement microservices architecture including service boundaries, communication patterns, API gateways, service mesh, service discovery, and distributed system patterns. Use when building microservices, distributed systems, or service-oriented architectures.
---

# Microservices Architecture

## Overview

Comprehensive guide to designing, implementing, and maintaining microservices architectures. Covers service decomposition, communication patterns, data management, deployment strategies, and observability for distributed systems.

## When to Use

- Designing new microservices architectures
- Decomposing monolithic applications
- Implementing service-to-service communication
- Setting up API gateways and service mesh
- Implementing service discovery
- Managing distributed transactions
- Designing inter-service data consistency
- Scaling independent services

## Instructions

### 1. **Service Boundary Design**

#### Domain-Driven Design (DDD) Approach
```
Bounded Contexts:
┌─────────────────┐  ┌─────────────────┐  ┌─────────────────┐
│  Order Service  │  │  User Service   │  │ Payment Service │
│                 │  │                 │  │                 │
│ - Create Order  │  │ - User Profile  │  │ - Process Pay   │
│ - Order Status  │  │ - Auth          │  │ - Refund        │
│ - Order History │  │ - Preferences   │  │ - Transactions  │
└─────────────────┘  └─────────────────┘  └─────────────────┘
```

**Decomposition Strategies:**

1. **By Business Capability**
```
E-commerce System:
- Product Catalog Service
- Shopping Cart Service
- Order Management Service
- Payment Service
- Inventory Service
- Shipping Service
- User Account Service
```

2. **By Subdomain**
```
Healthcare System:
- Patient Management (Core Domain)
- Appointment Scheduling (Core Domain)
- Billing (Supporting Domain)
- Notifications (Generic Domain)
- Reporting (Generic Domain)
```

#### Service Design Example
```typescript
// order-service/src/domain/order.ts
export class OrderService {
  constructor(
    private orderRepository: OrderRepository,
    private eventBus: EventBus,
    private paymentClient: PaymentClient,
    private inventoryClient: InventoryClient
  ) {}

  async createOrder(request: CreateOrderRequest): Promise<Order> {
    // 1. Validate order
    const order = Order.create(request);

    // 2. Check inventory (synchronous call)
    const available = await this.inventoryClient.checkAvailability(
      order.items
    );
    if (!available) {
      throw new InsufficientInventoryError();
    }

    // 3. Save order
    await this.orderRepository.save(order);

    // 4. Publish event (asynchronous)
    await this.eventBus.publish(new OrderCreatedEvent(order));

    return order;
  }
}
```

### 2. **Communication Patterns**

#### Synchronous Communication (REST/gRPC)

**REST API Example:**
```typescript
// user-service/src/api/user.controller.ts
import express from 'express';

const router = express.Router();

// Get user profile
router.get('/users/:id', async (req, res) => {
  try {
    const user = await userService.findById(req.params.id);
    res.json(user);
  } catch (error) {
    if (error instanceof UserNotFoundError) {
      res.status(404).json({ error: 'User not found' });
    } else {
      res.status(500).json({ error: 'Internal server error' });
    }
  }
});

// Service-to-service call with circuit breaker
import axios from 'axios';
import CircuitBreaker from 'opossum';

const options = {
  timeout: 3000,
  errorThresholdPercentage: 50,
  resetTimeout: 30000
};

const breaker = new CircuitBreaker(
  async (userId: string) => {
    const response = await axios.get(
      `http://user-service/users/${userId}`,
      { timeout: 2000 }
    );
    return response.data;
  },
  options
);

breaker.fallback(() => ({ id: userId, name: 'Unknown User' }));
```

**gRPC Example:**
```protobuf
// proto/user.proto
syntax = "proto3";

package user;

service UserService {
  rpc GetUser (GetUserRequest) returns (UserResponse);
  rpc ListUsers (ListUsersRequest) returns (stream UserResponse);
}

message GetUserRequest {
  string user_id = 1;
}

message UserResponse {
  string user_id = 1;
  string email = 2;
  string name = 3;
}
```

```typescript
// Implementation
import * as grpc from '@grpc/grpc-js';
import * as protoLoader from '@grpc/proto-loader';

const packageDefinition = protoLoader.loadSync('proto/user.proto');
const userProto = grpc.loadPackageDefinition(packageDefinition).user;

// Server
function getUser(call, callback) {
  const userId = call.request.user_id;
  const user = await userService.findById(userId);
  callback(null, user);
}

const server = new grpc.Server();
server.addService(userProto.UserService.service, { getUser });
server.bindAsync('0.0.0.0:50051', grpc.ServerCredentials.createInsecure());
```

#### Asynchronous Communication (Message Queue)

**Event-Driven with RabbitMQ:**
```typescript
// order-service/src/events/publisher.ts
import amqp from 'amqplib';

export class EventPublisher {
  private connection: amqp.Connection;
  private channel: amqp.Channel;

  async connect() {
    this.connection = await amqp.connect('amqp://localhost');
    this.channel = await this.connection.createChannel();
    await this.channel.assertExchange('orders', 'topic', { durable: true });
  }

  async publishOrderCreated(order: Order) {
    const event = {
      eventType: 'OrderCreated',
      timestamp: new Date(),
      data: order
    };

    this.channel.publish(
      'orders',
      'order.created',
      Buffer.from(JSON.stringify(event)),
      { persistent: true }
    );
  }
}

// inventory-service/src/events/consumer.ts
export class OrderEventConsumer {
  async subscribe() {
    const connection = await amqp.connect('amqp://localhost');
    const channel = await connection.createChannel();

    await channel.assertExchange('orders', 'topic', { durable: true });
    const q = await channel.assertQueue('inventory-order-events', {
      durable: true
    });

    await channel.bindQueue(q.queue, 'orders', 'order.created');

    channel.consume(q.queue, async (msg) => {
      if (msg) {
        const event = JSON.parse(msg.content.toString());
        await this.handleOrderCreated(event.data);
        channel.ack(msg);
      }
    });
  }

  private async handleOrderCreated(order: Order) {
    // Reserve inventory
    await inventoryService.reserveItems(order.items);
  }
}
```

**Kafka Event Streaming:**
```typescript
// event-streaming/kafka-producer.ts
import { Kafka } from 'kafkajs';

const kafka = new Kafka({
  clientId: 'order-service',
  brokers: ['kafka:9092']
});

const producer = kafka.producer();

export async function publishEvent(topic: string, event: any) {
  await producer.connect();
  await producer.send({
    topic,
    messages: [
      {
        key: event.aggregateId,
        value: JSON.stringify(event),
        headers: {
          'event-type': event.type,
          'correlation-id': event.correlationId
        }
      }
    ]
  });
}

// Consumer
const consumer = kafka.consumer({ groupId: 'inventory-service' });

await consumer.subscribe({ topic: 'order-events', fromBeginning: false });

await consumer.run({
  eachMessage: async ({ topic, partition, message }) => {
    const event = JSON.parse(message.value.toString());
    await eventHandler.handle(event);
  }
});
```

### 3. **API Gateway Pattern**

```typescript
// api-gateway/src/gateway.ts
import express from 'express';
import httpProxy from 'http-proxy-middleware';
import jwt from 'jsonwebtoken';
import rateLimit from 'express-rate-limit';

const app = express();

// Rate limiting
const limiter = rateLimit({
  windowMs: 15 * 60 * 1000, // 15 minutes
  max: 100
});

app.use(limiter);

// Authentication middleware
const authenticateToken = (req, res, next) => {
  const token = req.headers['authorization']?.split(' ')[1];
  if (!token) return res.sendStatus(401);

  jwt.verify(token, process.env.JWT_SECRET, (err, user) => {
    if (err) return res.sendStatus(403);
    req.user = user;
    next();
  });
};

// Route to services
app.use('/api/users', authenticateToken, httpProxy.createProxyMiddleware({
  target: 'http://user-service:3000',
  changeOrigin: true,
  pathRewrite: { '^/api/users': '/users' }
}));

app.use('/api/orders', authenticateToken, httpProxy.createProxyMiddleware({
  target: 'http://order-service:3000',
  changeOrigin: true,
  pathRewrite: { '^/api/orders': '/orders' }
}));

app.use('/api/products', httpProxy.createProxyMiddleware({
  target: 'http://product-service:3000',
  changeOrigin: true,
  pathRewrite: { '^/api/products': '/products' }
}));

// Aggregation endpoint
app.get('/api/order-details/:orderId', authenticateToken, async (req, res) => {
  const orderId = req.params.orderId;

  // Parallel requests to multiple services
  const [order, user, products] = await Promise.all([
    fetch(`http://order-service:3000/orders/${orderId}`).then(r => r.json()),
    fetch(`http://user-service:3000/users/${req.user.id}`).then(r => r.json()),
    fetch(`http://product-service:3000/products?ids=${order.itemIds}`).then(r => r.json())
  ]);

  res.json({ order, user, products });
});
```

### 4. **Service Discovery**

#### Consul Example
```typescript
// service-registry/consul-client.ts
import Consul from 'consul';

export class ServiceRegistry {
  private consul: Consul.Consul;

  constructor() {
    this.consul = new Consul({
      host: 'consul',
      port: 8500
    });
  }

  // Register service
  async register(serviceName: string, servicePort: number) {
    await this.consul.agent.service.register({
      id: `${serviceName}-${process.env.HOSTNAME}`,
      name: serviceName,
      address: process.env.SERVICE_IP,
      port: servicePort,
      check: {
        http: `http://${process.env.SERVICE_IP}:${servicePort}/health`,
        interval: '10s',
        timeout: '5s'
      }
    });
  }

  // Discover service
  async discover(serviceName: string): Promise<string> {
    const result = await this.consul.health.service({
      service: serviceName,
      passing: true
    });

    if (result.length === 0) {
      throw new Error(`Service ${serviceName} not found`);
    }

    // Simple round-robin
    const service = result[Math.floor(Math.random() * result.length)];
    return `http://${service.Service.Address}:${service.Service.Port}`;
  }

  // Deregister on shutdown
  async deregister(serviceId: string) {
    await this.consul.agent.service.deregister(serviceId);
  }
}
```

#### Kubernetes Service Discovery
```yaml
# user-service-deployment.yaml
apiVersion: v1
kind: Service
metadata:
  name: user-service
spec:
  selector:
    app: user-service
  ports:
    - protocol: TCP
      port: 80
      targetPort: 3000
  type: ClusterIP
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: user-service
spec:
  replicas: 3
  selector:
    matchLabels:
      app: user-service
  template:
    metadata:
      labels:
        app: user-service
    spec:
      containers:
      - name: user-service
        image: user-service:latest
        ports:
        - containerPort: 3000
        env:
        - name: SERVICE_NAME
          value: "user-service"
```

```typescript
// Service call in Kubernetes
const userServiceUrl = process.env.USER_SERVICE_URL || 'http://user-service';
const response = await fetch(`${userServiceUrl}/users/${userId}`);
```

### 5. **Data Consistency Patterns**

#### Saga Pattern (Orchestration)
```typescript
// order-saga-orchestrator.ts
export class OrderSagaOrchestrator {
  async createOrder(orderData: CreateOrderRequest) {
    const sagaId = uuidv4();
    const saga = new SagaInstance(sagaId);

    try {
      // Step 1: Create order
      const order = await this.orderService.createOrder(orderData);
      saga.addCompensation(() => this.orderService.cancelOrder(order.id));

      // Step 2: Reserve inventory
      await this.inventoryService.reserveItems(order.items);
      saga.addCompensation(() =>
        this.inventoryService.releaseReservation(order.id)
      );

      // Step 3: Process payment
      const payment = await this.paymentService.charge(order.total);
      saga.addCompensation(() =>
        this.paymentService.refund(payment.id)
      );

      // Step 4: Confirm order
      await this.orderService.confirmOrder(order.id);

      return order;
    } catch (error) {
      // Compensate in reverse order
      await saga.compensate();
      throw error;
    }
  }
}
```

#### Event Sourcing Pattern
```typescript
// order-aggregate.ts
export class OrderAggregate {
  private id: string;
  private status: OrderStatus;
  private items: OrderItem[];
  private events: DomainEvent[] = [];

  // Command handler
  createOrder(command: CreateOrderCommand) {
    // Validation
    if (this.id) throw new Error('Order already exists');

    // Apply event
    this.apply(new OrderCreatedEvent({
      orderId: command.orderId,
      userId: command.userId,
      items: command.items
    }));
  }

  // Event handler
  private apply(event: DomainEvent) {
    switch (event.type) {
      case 'OrderCreated':
        this.id = event.orderId;
        this.items = event.items;
        this.status = OrderStatus.PENDING;
        break;
      case 'OrderConfirmed':
        this.status = OrderStatus.CONFIRMED;
        break;
    }
    this.events.push(event);
  }

  getUncommittedEvents(): DomainEvent[] {
    return this.events;
  }
}
```

### 6. **Service Mesh (Istio)**

```yaml
# istio-config.yaml
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: order-service
spec:
  hosts:
  - order-service
  http:
  - match:
    - headers:
        user-type:
          exact: premium
    route:
    - destination:
        host: order-service
        subset: v2
      weight: 100
  - route:
    - destination:
        host: order-service
        subset: v1
      weight: 90
    - destination:
        host: order-service
        subset: v2
      weight: 10
---
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: order-service
spec:
  host: order-service
  trafficPolicy:
    connectionPool:
      tcp:
        maxConnections: 100
      http:
        http1MaxPendingRequests: 50
        maxRequestsPerConnection: 2
    outlierDetection:
      consecutiveErrors: 5
      interval: 30s
      baseEjectionTime: 30s
  subsets:
  - name: v1
    labels:
      version: v1
  - name: v2
    labels:
      version: v2
```

## Best Practices

### ✅ DO
- Design services around business capabilities
- Use asynchronous communication where possible
- Implement circuit breakers for resilience
- Use API gateway for cross-cutting concerns
- Implement distributed tracing
- Use service mesh for service-to-service communication
- Design for failure (chaos engineering)
- Implement health checks for all services
- Use correlation IDs for request tracking
- Version your APIs
- Implement proper monitoring and alerting
- Use event-driven architecture for loose coupling
- Implement idempotent operations
- Use database per service pattern

### ❌ DON'T
- Share databases between services
- Create overly granular services (nanoservices)
- Use distributed transactions (two-phase commit)
- Ignore network latency and failures
- Share domain models between services
- Deploy all services as one unit
- Hardcode service URLs
- Forget to implement authentication/authorization
- Use synchronous calls for long-running operations
- Ignore backward compatibility
- Skip monitoring and logging
- Create circular dependencies between services

## Common Patterns

### Pattern 1: Backend for Frontend (BFF)
```typescript
// mobile-bff/src/api.ts - Optimized for mobile
app.get('/api/home', async (req, res) => {
  const [featured, recommendations] = await Promise.all([
    productService.getFeatured(5),
    recommendationService.getForUser(req.user.id, 10)
  ]);
  res.json({ featured, recommendations });
});

// web-bff/src/api.ts - More data for web
app.get('/api/home', async (req, res) => {
  const [featured, recommendations, categories, promotions] = await Promise.all([
    productService.getFeatured(20),
    recommendationService.getForUser(req.user.id, 50),
    categoryService.getAll(),
    promotionService.getActive()
  ]);
  res.json({ featured, recommendations, categories, promotions });
});
```

### Pattern 2: Sidecar Pattern
```yaml
# Pod with sidecar
apiVersion: v1
kind: Pod
metadata:
  name: app-with-sidecar
spec:
  containers:
  - name: app
    image: my-app:latest
  - name: logging-sidecar
    image: fluentd:latest
    volumeMounts:
    - name: logs
      mountPath: /logs
  volumes:
  - name: logs
    emptyDir: {}
```

## Tools & Resources

- **Service Mesh**: Istio, Linkerd, Consul Connect
- **API Gateway**: Kong, Apigee, AWS API Gateway
- **Service Discovery**: Consul, Eureka, Zookeeper
- **Message Queue**: RabbitMQ, Apache Kafka, AWS SQS
- **Orchestration**: Kubernetes, Docker Swarm, Nomad
- **Monitoring**: Prometheus, Grafana, Datadog
- **Tracing**: Jaeger, Zipkin, AWS X-Ray
- **Circuit Breaker**: Hystrix, Resilience4j, Polly

Overview

This skill guides design and implementation of microservices architectures for scalable, maintainable distributed systems. It covers service decomposition, communication patterns, API gateways, service discovery, data consistency patterns, and service mesh configurations. Use it to plan service boundaries, choose communication styles, and apply operational patterns for production systems.

How this skill works

The skill inspects architecture goals and recommends decomposition strategies using Domain-Driven Design and business-capability approaches. It explains synchronous (REST/gRPC) and asynchronous (message queues, Kafka) communication, shows API gateway patterns for routing and aggregation, and details service discovery with Consul and Kubernetes. It also covers distributed data consistency patterns (Sagas, Event Sourcing) and service mesh configuration (Istio) for traffic control and resilience.

When to use it

  • Designing a new microservices-based system from a monolith
  • Decomposing services by domain or capability
  • Choosing between REST, gRPC, or event-driven communication
  • Implementing API gateways, aggregation, or rate limiting
  • Setting up service discovery in Consul or Kubernetes
  • Applying sagas or event sourcing for cross-service consistency

Best practices

  • Define clear bounded contexts and align services to business capabilities
  • Prefer asynchronous events for decoupling and scalability where possible
  • Use circuit breakers and timeouts for all synchronous service calls
  • Place observability (metrics, logs, tracing) in the design from day one
  • Automate service registration and health checks for discovery and load balancing
  • Model compensations for long-running transactions with the Saga pattern

Example use cases

  • E-commerce: separate catalog, orders, inventory, payments, and user services with event-driven stock updates
  • Monolith decomposition: extract a single business capability as a service and add API gateway routing
  • Resilient inter-service calls: add circuit breakers, retries, and fallbacks for user-service requests
  • Cross-service transaction: implement an orchestrated saga to create orders, reserve inventory, and charge payments
  • Kubernetes deployment: use ClusterIP services for discovery and envoy/istio for traffic shaping

FAQ

How do I choose between synchronous and asynchronous communication?

Use synchronous calls for low-latency request/response needs and async events when you need loose coupling, scalability, and eventual consistency.

When should I use a service mesh?

Adopt a service mesh when you need advanced traffic management, observability, mTLS, and fine-grained policies across many services; start simple and add it when operational complexity grows.