# Microservices Architecture

## 📚 สารบัญ

1. [หลักการพื้นฐาน](#หลักการพื้นฐาน)
2. [โครงสร้างของ Microservices](#โครงสร้างของ-microservices)
3. [ข้อดี และข้อเสีย](#ข้อดี-และข้อเสีย)
4. [Microservices Patterns](#microservices-patterns)
5. [Code Examples](#code-examples)
6. [Real World Examples](#real-world-examples)
7. [Best Practices](#best-practices)

---

## 🎯 หลักการพื้นฐาน

### Microservices Architecture คืออะไร?

**นิยาม:** สถาปัตยกรรมที่แบ่งระบบออกเป็น services ขนาดเล็ก (microservices) โดยแต่ละ service:

- ✓ มีฐานข้อมูลของตัวเอง (Database per service)
- ✓ ติดต่อกันผ่าน APIs (REST, gRPC, Message Queues)
- ✓ Deploy อิสระ (Independent deployment)
- ✓ Developed โดย separate teams
- ✓ Technology-agnostic

### หลักการหลัก

```
1️⃣  Service Independence
   - Each service is separate
   - Own database, own team
   - Can be developed independently

2️⃣  Decoupling
   - Services loosely coupled
   - Communicate via APIs
   - Change one ไม่กระทบ others

3️⃣  Scalability
   - Scale each service independently
   - Scale User Service 10x, others 2x
   - Resource efficient

4️⃣  Technology Diversity
   - Use best tool for each job
   - Service A: Node.js
   - Service B: Java
   - Service C: Python

5️⃣  Failure Isolation
   - Service failure ≠ system down
   - Other services still work
   - Graceful degradation

6️⃣  Distributed System
   - Network latency
   - Partial failures
   - Eventual consistency
```

---

## 🏗️ โครงสร้างของ Microservices

### Typical Microservices Architecture

```
┌──────────────────────────────────────────────────────────────┐
│                    CLIENT LAYER                              │
│  (Web Browser / Mobile App / Desktop Application)            │
└──────────────────────────┬─────────────────────────────────┘
                           ↓↑
┌──────────────────────────────────────────────────────────────┐
│              API GATEWAY / LOAD BALANCER                     │
│  - Request routing                                           │
│  - Authentication                                            │
│  - Rate limiting                                             │
│  - Request/Response transformation                           │
└──────────────────────────┬─────────────────────────────────┘
                           ↓↑
    ┌──────────────┬──────────────┬──────────────┐
    ↓↑             ↓↑             ↓↑
┌─────────────┐ ┌──────────────┐ ┌─────────────┐
│ User        │ │ Product      │ │ Order       │
│ Service     │ │ Service      │ │ Service     │
├─────────────┤ ├──────────────┤ ├─────────────┤
│ - Register  │ │ - Browse     │ │ - Create    │
│ - Login     │ │ - Search     │ │ - Checkout  │
│ - Profile   │ │ - Details    │ │ - Track     │
│ - Logout    │ │ - Reviews    │ │ - Cancel    │
└────────┬────┘ └───────┬──────┘ └────────┬────┘
         ↓↑             ↓↑             ↓↑
      ┌──────────┐  ┌──────────┐  ┌──────────┐
      │ User DB  │  │Product DB│  │Order DB  │
      └──────────┘  └──────────┘  └──────────┘

┌──────────────┬──────────────┬──────────────┐
↓↑             ↓↑             ↓↑
┌─────────────┐ ┌──────────────┐ ┌──────────────┐
│ Payment     │ │ Notification │ │ Inventory    │
│ Service     │ │ Service      │ │ Service      │
├─────────────┤ ├──────────────┤ ├──────────────┤
│ - Process   │ │ - Email      │ │ - Check      │
│ - Refund    │ │ - SMS        │ │ - Update     │
│ - Validate  │ │ - Push       │ │ - Reserve    │
└────────┬────┘ └───────┬──────┘ └────────┬────┘
         ↓↑             ↓↑             ↓↑
      ┌──────────┐  ┌──────────┐  ┌──────────┐
      │Payment DB│  │  Queue   │  │Inventory │
      └──────────┘  └──────────┘  │   DB     │
                                  └──────────┘

┌────────────────────────────────────────────┐
│  SERVICE DISCOVERY & REGISTRY              │
│  (Consul, Eureka, Kubernetes)              │
└────────────────────────────────────────────┘

┌────────────────────────────────────────────┐
│  MESSAGE BROKER / EVENT BUS                │
│  (RabbitMQ, Kafka, AWS SNS/SQS)            │
└────────────────────────────────────────────┘

┌────────────────────────────────────────────┐
│  MONITORING & LOGGING                      │
│  (ELK Stack, Prometheus, Datadog)          │
└────────────────────────────────────────────┘
```

### Service Characteristics

```
User Service:
├── Responsibilities
│   ├── User registration
│   ├── Authentication
│   ├── Profile management
│   └── Authorization
├── API Endpoints
│   ├── POST /users (register)
│   ├── POST /auth/login
│   ├── GET /users/{id}
│   └── PUT /users/{id}
├── Database
│   └── users_db (separate)
└── Technology
    └── Node.js + Express

Product Service:
├── Responsibilities
│   ├── Product catalog
│   ├── Search & filtering
│   ├── Reviews & ratings
│   └── Inventory levels
├── API Endpoints
│   ├── GET /products
│   ├── GET /products/{id}
│   ├── POST /products/{id}/reviews
│   └── GET /products/{id}/inventory
├── Database
│   └── products_db (separate)
└── Technology
    └── Java + Spring Boot

Order Service:
├── Responsibilities
│   ├── Order creation
│   ├── Order management
│   ├── Order history
│   └── Order cancellation
├── API Endpoints
│   ├── POST /orders
│   ├── GET /orders/{id}
│   ├── PUT /orders/{id}/cancel
│   └── GET /orders (user's orders)
├── Database
│   └── orders_db (separate)
└── Technology
    └── Python + Flask
```

---

## ✅ ข้อดี และข้อเสีย

### ✅ ข้อดี

| ข้อดี                      | อธิบาย                               |
| -------------------------- | ------------------------------------ |
| **Independent Scaling**    | Scale ตามความต้องการของแต่ละ service |
| **Independent Deployment** | Deploy service A ไม่กระทบ others     |
| **Technology Diversity**   | Use best tech for each service       |
| **Fault Isolation**        | Service down ≠ system down           |
| **Team Independence**      | Teams can work independently         |
| **Faster Development**     | Smaller teams, faster iteration      |
| **Easier to Understand**   | Each service ฟอกัส narrow scope      |
| **Resilience**             | System can degrade gracefully        |
| **Reusability**            | Services can be reused               |

### ❌ ข้อเสีย

| ข้อเสีย                      | อธิบาย                          |
| ---------------------------- | ------------------------------- |
| **Complexity**               | Distributed system ซับซ้อน      |
| **Network Latency**          | Inter-service calls ช้า         |
| **Testing**                  | Integration testing ยาก         |
| **Monitoring**               | Need sophisticated monitoring   |
| **Deployment**               | DevOps expertise ต้อง           |
| **Data Consistency**         | Eventual consistency challenges |
| **Distributed Transactions** | Saga pattern needed             |
| **Network Failure**          | Partial failures ต้องจัดการ     |
| **Operational Overhead**     | More infrastructure             |
| **Learning Curve**           | Complex concepts                |

### เมื่อไดควรใช้ Microservices?

```
✅ ใช้เมื่อ:
- Large team (50-1000+ developers)
- Large project with distinct domains
- Need independent scaling
- Need independent deployment
- Different tech stacks per service
- High-traffic system
- Long-term project
- Multiple independent deployments needed
- Different SLAs per service

❌ ไม่ใช้เมื่อ:
- Small team (< 20 developers)
- Small project
- Simple business logic
- Frequent schema changes
- Real-time distributed transactions needed
- Low latency critical
- Limited DevOps expertise
- Early stage startup
```

---

## 🔄 Microservices Patterns

### 1. Service-to-Service Communication

#### Synchronous (REST, gRPC)

```javascript
// User Service calling Product Service
const axios = require("axios");

// ❌ BAD: Hardcoded URL
const productResponse = await axios.get("http://localhost:3002/products/123");

// ✅ GOOD: Service Discovery
const productServiceUrl = await serviceRegistry.discover("product-service");
const productResponse = await axios.get(`${productServiceUrl}/products/123`);

// ✅ BETTER: With retry & circuit breaker
const ProductService = require("./services/ProductService");
try {
  const product = await ProductService.getProduct(123);
} catch (error) {
  if (error.status === 503) {
    // Product service down - use fallback
    return { id: 123, name: "Unknown", price: 0 };
  }
}
```

#### Asynchronous (Message Queue)

```javascript
// Order Service publishes event
// When order created, send message to Kafka

const kafka = require("kafkajs");
const producer = new kafka.Kafka({ brokers: ["kafka:9092"] }).producer();

async function createOrder(orderData) {
  const order = await saveOrderToDb(orderData);

  // Publish event
  await producer.send({
    topic: "order-created",
    messages: [
      {
        key: String(order.id),
        value: JSON.stringify({
          orderId: order.id,
          userId: order.userId,
          amount: order.total,
          timestamp: new Date(),
        }),
      },
    ],
  });

  return order;
}

// Notification Service subscribes
const consumer = kafka.consumer({ groupId: "notification-service" });

await consumer.subscribe({ topic: "order-created" });
await consumer.run({
  eachMessage: async ({ message }) => {
    const event = JSON.parse(message.value);
    await notificationService.sendOrderConfirmation(event.userId);
  },
});
```

### 2. Data Management Pattern

#### Database per Service

```javascript
// ❌ BAD: All services share one database
// User Service + Product Service share same DB
const db = require("shared-database");

// ✅ GOOD: Database per service
// User Service
const userDb = require("mysql").createConnection({
  host: "user-db-server",
  database: "user_service_db",
});

// Product Service
const productDb = require("mysql").createConnection({
  host: "product-db-server",
  database: "product_service_db",
});

// If Order Service needs user + product data:
// 1. Call User Service API to get user info
// 2. Call Product Service API to get product info
// 3. Combine results in Order Service
```

### 3. Distributed Transaction Pattern (Saga)

```javascript
// Choreography-based Saga (Event-driven)
// Example: Create Order Saga

// 1. Order Service creates order
async function createOrder(orderData) {
  const order = await orderDb.save(orderData);

  // Publish event
  await eventBus.publish("order.created", {
    orderId: order.id,
    userId: order.userId,
    items: order.items,
  });

  return order;
}

// 2. Inventory Service listens & reserves stock
await eventBus.subscribe("order.created", async (event) => {
  try {
    await inventoryService.reserveItems(event.items);

    // Publish success event
    await eventBus.publish("inventory.reserved", {
      orderId: event.orderId,
    });
  } catch (error) {
    // Publish failure - trigger rollback
    await eventBus.publish("inventory.reservation-failed", {
      orderId: event.orderId,
      reason: error.message,
    });
  }
});

// 3. Payment Service listens & processes payment
await eventBus.subscribe("inventory.reserved", async (event) => {
  try {
    await paymentService.charge(event.orderId);

    await eventBus.publish("payment.completed", {
      orderId: event.orderId,
    });
  } catch (error) {
    // Compensating transaction (refund)
    await eventBus.publish("payment.failed", {
      orderId: event.orderId,
    });

    // Trigger rollback in Inventory Service
    await inventoryService.releaseReservedItems(event.orderId);
  }
});

// 4. Order Service listens & updates order status
await eventBus.subscribe("payment.completed", async (event) => {
  await orderDb.update(event.orderId, { status: "confirmed" });
});

await eventBus.subscribe("payment.failed", async (event) => {
  await orderDb.update(event.orderId, { status: "failed" });
});
```

### 4. Service Discovery Pattern

```javascript
// Service Registry (Consul example)
// When service starts, register itself

const consul = require("consul");
const consulClient = new consul({
  host: "consul-server",
  port: 8500,
});

// Register User Service
async function registerService() {
  await consulClient.agent.service.register({
    id: `user-service-${process.env.INSTANCE_ID}`,
    name: "user-service",
    address: process.env.SERVICE_HOST,
    port: parseInt(process.env.SERVICE_PORT),
    check: {
      http: `http://${process.env.SERVICE_HOST}:${process.env.SERVICE_PORT}/health`,
      interval: "10s",
      timeout: "5s",
    },
  });
}

// Discover Product Service
async function getProductService() {
  const services = await consulClient.health.service({
    service: "product-service",
    passing: true,
  });

  if (services.length === 0) {
    throw new Error("Product service not available");
  }

  const service = services[0].Service;
  return `http://${service.Address}:${service.Port}`;
}
```

### 5. API Gateway Pattern

```javascript
// API Gateway routes requests to services
const express = require("express");
const httpProxy = require("express-http-proxy");

const app = express();

// Routes
app.use("/api/users", httpProxy("http://user-service:3001"));
app.use("/api/products", httpProxy("http://product-service:3002"));
app.use("/api/orders", httpProxy("http://order-service:3003"));

// Authentication middleware (centralized)
app.use("/api/*", async (req, res, next) => {
  const token = req.headers.authorization;
  try {
    const user = await validateToken(token);
    req.user = user;
    next();
  } catch (error) {
    res.status(401).json({ error: "Unauthorized" });
  }
});

// Rate limiting (centralized)
const rateLimit = require("express-rate-limit");
const limiter = rateLimit({
  windowMs: 15 * 60 * 1000,
  max: 100,
});
app.use("/api/", limiter);

// Request logging (centralized)
app.use((req, res, next) => {
  console.log(`${req.method} ${req.path}`);
  next();
});

app.listen(3000, () => console.log("API Gateway running"));
```

### 6. Circuit Breaker Pattern

```javascript
// Circuit Breaker for resilience
class CircuitBreaker {
  constructor(request, failureThreshold = 5, resetTimeout = 60000) {
    this.request = request;
    this.failureCount = 0;
    this.failureThreshold = failureThreshold;
    this.resetTimeout = resetTimeout;
    this.state = "CLOSED"; // CLOSED | OPEN | HALF_OPEN
  }

  async call(args) {
    if (this.state === "OPEN") {
      if (Date.now() - this.lastFailureTime > this.resetTimeout) {
        this.state = "HALF_OPEN";
      } else {
        throw new Error("Circuit breaker is OPEN");
      }
    }

    try {
      const result = await this.request(args);
      this.onSuccess();
      return result;
    } catch (error) {
      this.onFailure();
      throw error;
    }
  }

  onSuccess() {
    this.failureCount = 0;
    this.state = "CLOSED";
  }

  onFailure() {
    this.failureCount++;
    this.lastFailureTime = Date.now();

    if (this.failureCount >= this.failureThreshold) {
      this.state = "OPEN";
    }
  }
}

// Usage
const productServiceBreaker = new CircuitBreaker(async (productId) => {
  const response = await axios.get(
    `http://product-service/products/${productId}`
  );
  return response.data;
});

// Call with circuit breaker
try {
  const product = await productServiceBreaker.call(123);
} catch (error) {
  console.log("Product service unavailable, using fallback");
  return { id: 123, name: "Unknown", price: 0 };
}
```

---

## 💻 Code Examples

### Example 1: Order Service (Node.js)

```javascript
// order-service/src/controllers/OrderController.js
class OrderController {
  async createOrder(req, res) {
    try {
      const { userId, items } = req.body;

      // Create order
      const order = await OrderService.createOrder(userId, items);

      // Publish event
      await EventBus.publish("order.created", {
        orderId: order.id,
        userId: order.userId,
        items: order.items,
        total: order.total,
      });

      res.status(201).json(order);
    } catch (error) {
      res.status(400).json({ error: error.message });
    }
  }
}

// order-service/src/services/OrderService.js
class OrderService {
  async createOrder(userId, items) {
    // Validate user exists (call User Service)
    const user = await UserServiceClient.getUser(userId);
    if (!user) throw new Error("User not found");

    // Calculate total
    let total = 0;
    for (const item of items) {
      const product = await ProductServiceClient.getProduct(item.productId);
      total += product.price * item.quantity;
    }

    // Save order
    const order = await OrderRepository.save({
      userId,
      items,
      total,
      status: "pending",
      createdAt: new Date(),
    });

    return order;
  }
}

// order-service/src/services/UserServiceClient.js
class UserServiceClient {
  async getUser(userId) {
    try {
      const userServiceUrl = await ServiceRegistry.discover("user-service");
      const response = await axios.get(`${userServiceUrl}/users/${userId}`);
      return response.data;
    } catch (error) {
      return null;
    }
  }
}
```

### Example 2: Notification Service (Python)

```python
# notification-service/main.py
from kafka import KafkaConsumer
from flask import Flask
import json
import smtplib

app = Flask(__name__)
consumer = KafkaConsumer(
    'order-created',
    bootstrap_servers=['kafka:9092'],
    value_deserializer=lambda m: json.loads(m.decode('utf-8')),
    group_id='notification-service'
)

# Health check endpoint
@app.route('/health')
def health():
    return {'status': 'OK'}, 200

# Listen for events
def listen_to_events():
    for message in consumer:
        event = message.value
        send_order_confirmation(event['userId'], event['orderId'])

def send_order_confirmation(user_id, order_id):
    # Get user email from User Service
    user = requests.get(f'http://user-service:3001/users/{user_id}').json()

    # Send email
    try:
        msg = f"Your order {order_id} has been created!"
        smtplib.SMTP('localhost').sendmail(
            'orders@example.com',
            user['email'],
            msg
        )
        print(f"Email sent to {user['email']}")
    except Exception as e:
        print(f"Failed to send email: {e}")

if __name__ == '__main__':
    # Start listening in background thread
    import threading
    threading.Thread(target=listen_to_events, daemon=True).start()

    # Start Flask app
    app.run(host='0.0.0.0', port=3004)
```

### Example 3: Deployment (Docker Compose)

```yaml
version: "3.8"

services:
  # API Gateway
  api-gateway:
    build: ./api-gateway
    ports:
      - "3000:3000"
    environment:
      - NODE_ENV=production
    depends_on:
      - user-service
      - product-service
      - order-service

  # User Service
  user-service:
    build: ./services/user-service
    environment:
      - DB_HOST=user-db
      - CONSUL_HOST=consul
    depends_on:
      - user-db
      - consul

  # Product Service
  product-service:
    build: ./services/product-service
    environment:
      - DB_HOST=product-db
      - CONSUL_HOST=consul
    depends_on:
      - product-db
      - consul

  # Order Service
  order-service:
    build: ./services/order-service
    environment:
      - DB_HOST=order-db
      - KAFKA_BROKERS=kafka:9092
      - CONSUL_HOST=consul
    depends_on:
      - order-db
      - kafka
      - consul

  # Notification Service
  notification-service:
    build: ./services/notification-service
    environment:
      - KAFKA_BROKERS=kafka:9092
    depends_on:
      - kafka

  # Databases
  user-db:
    image: mysql:8
    environment:
      - MYSQL_DATABASE=user_db
      - MYSQL_ROOT_PASSWORD=root

  product-db:
    image: mysql:8
    environment:
      - MYSQL_DATABASE=product_db
      - MYSQL_ROOT_PASSWORD=root

  order-db:
    image: mysql:8
    environment:
      - MYSQL_DATABASE=order_db
      - MYSQL_ROOT_PASSWORD=root

  # Message Broker
  kafka:
    image: confluentinc/cp-kafka:latest
    environment:
      KAFKA_BROKER_ID: 1
      KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181

  zookeeper:
    image: confluentinc/cp-zookeeper:latest

  # Service Registry
  consul:
    image: consul:latest
    ports:
      - "8500:8500"

  # Monitoring
  prometheus:
    image: prom/prometheus:latest
    ports:
      - "9090:9090"
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml

  grafana:
    image: grafana/grafana:latest
    ports:
      - "3001:3000"
    depends_on:
      - prometheus
```

---

## 🌍 Real World Examples

### Example 1: Netflix (Microservices at Scale)

```
Netflix Architecture:
├── API Gateway
│   ├── Zuul (API Gateway)
│   └── Eureka (Service Discovery)
│
├── Frontend Services
│   ├── Web Service
│   ├── Mobile Service
│   └── TV Service
│
├── Core Services
│   ├── Authentication Service
│   ├── User Preferences Service
│   ├── Content Service
│   ├── Recommendation Service
│   ├── Billing Service
│   └── Notification Service
│
├── Data Layer
│   ├── Cassandra (Distributed DB)
│   ├── ElasticSearch
│   ├── Redis Cache
│   └── S3 (Video Storage)
│
└── Messaging
    ├── Kafka (Event Streaming)
    └── RabbitMQ

Key Features:
- Chaos Engineering (intentional failures)
- Circuit breakers for resilience
- Service-to-service security (mTLS)
- Comprehensive monitoring
```

### Example 2: Uber (Microservices for Real-time)

```
Uber Architecture:
├── API Gateway
│
├── Rider Services
│   ├── Trip Service
│   ├── Matching Service
│   ├── Routing Service
│   └── Billing Service
│
├── Driver Services
│   ├── Driver Management Service
│   ├── Dispatch Service
│   └── Rating Service
│
├── Real-time Services
│   ├── Location Tracking Service
│   ├── Geospatial Service
│   └── Real-time Notification Service
│
└── Infrastructure
    ├── Kafka (event streaming)
    ├── Redis (real-time data)
    └── Cassandra (high-volume storage)

Challenges Solved:
- Real-time GPS tracking
- Millisecond matching
- Handling surges (10,000+ requests/sec)
- Geographic distribution
```

### Example 3: Amazon (Monolith to Microservices)

```
Amazon's Journey:
1. Started: Monolithic system
2. Problem: Can't scale teams
3. Solution: Microservices + Service-Oriented Architecture (SOA)
4. Result:
   - Each team owns service
   - Can scale independently
   - Use different tech stacks
   - Deploy independently

Modern Amazon:
- 100,000+ microservices
- Thousands of development teams
- AWS EC2, ECS, Lambda
- DynamoDB for distributed data
- SQS/SNS for messaging
- Elasticsearch for search
```

---

## 🛡️ Best Practices

### 1. Design Services Around Business Domains

```javascript
// ❌ BAD: Technical boundaries
-DatabaseService -
  CacheService -
  AuthenticationService -
  // ✅ GOOD: Business domains (Domain-Driven Design)
  UserService(Authentication, Profile, Preferences) -
  ProductService(Catalog, Reviews, Ratings) -
  OrderService(Creating, Fulfillment, Tracking) -
  PaymentService(Processing, Refunds) -
  NotificationService(Email, SMS, Push);
```

### 2. Service Communication Guidelines

```javascript
// ✅ Use synchronous (REST) for:
- Read operations
- Real-time requirements
- Simple request-response

// ✅ Use asynchronous (messaging) for:
- Write operations
- Event notifications
- Background processing
- Decoupling services
```

### 3. Implementing Resilience

```javascript
// ✅ Circuit Breaker
async function callProductService(productId) {
  try {
    return await circuitBreaker.call(() => productServiceClient.get(productId));
  } catch (error) {
    // Fallback
    return getCachedProduct(productId) || getDefaultProduct();
  }
}

// ✅ Retry Logic with Exponential Backoff
async function callWithRetry(fn, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await fn();
    } catch (error) {
      if (i === maxRetries - 1) throw error;
      const delay = Math.pow(2, i) * 1000;
      await sleep(delay);
    }
  }
}

// ✅ Timeout
async function callWithTimeout(promise, timeoutMs = 5000) {
  return Promise.race([
    promise,
    new Promise((_, reject) =>
      setTimeout(() => reject(new Error("Timeout")), timeoutMs)
    ),
  ]);
}
```

### 4. Data Consistency Strategy

```javascript
// ✅ Eventually Consistent
// Order Service + Inventory Service

// 1. Create order
const order = await orderDb.save(orderData);

// 2. Publish event
await eventBus.publish("order.created", {
  orderId: order.id,
  items: order.items,
});

// 3. Eventually, Inventory Service updates stock
// (might take milliseconds to minutes)
await inventoryDb.decrementStock(order.items);

// ❌ AVOID: Two-phase commit (blocking, slow)
```

### 5. API Versioning

```javascript
// ✅ Version in URL (clear, easy to route)
GET / api / v1 / users / { id }; // Old version
GET / api / v2 / users / { id }; // New version

// ✅ Version in header (less visible)
GET / api / users / { id };
Header: Accept: application / vnd.myapi.v2 + json;

// Maintain multiple versions simultaneously
app.use("/api/v1/", userServiceV1);
app.use("/api/v2/", userServiceV2);
```

### 6. Monitoring & Observability

```javascript
// ✅ Distributed Tracing
const tracer = require("opentelemetry-api").trace.getTracer("my-service");

app.use((req, res, next) => {
  const span = tracer.startSpan(`${req.method} ${req.path}`);
  span.setAttributes({
    "http.method": req.method,
    "http.url": req.url,
    "http.client_ip": req.ip,
  });

  res.on("finish", () => {
    span.setAttributes({ "http.status_code": res.statusCode });
    span.end();
  });

  next();
});

// ✅ Metrics
const prometheus = require("prom-client");
const httpRequestDuration = new prometheus.Histogram({
  name: "http_request_duration_seconds",
  help: "Duration of HTTP requests in seconds",
});

app.use((req, res, next) => {
  const start = Date.now();
  res.on("finish", () => {
    const duration = (Date.now() - start) / 1000;
    httpRequestDuration.observe(duration);
  });
  next();
});
```

### 7. Testing Microservices

```javascript
// ✅ Unit Test (service isolation)
describe('OrderService', () => {
  test('should create order', async () => {
    const mockUserClient = {
      getUser: jest.fn().mockResolvedValue({ id: 1, name: 'John' })
    };
    const service = new OrderService(mockUserClient, mockDb);
    const order = await service.createOrder(1, [...items]);
    expect(order.id).toBeDefined();
  });
});

// ✅ Integration Test (service + external)
describe('Order Service Integration', () => {
  test('should call User Service', async () => {
    const server = await startOrderService();
    const response = await axios.post('http://localhost:3003/orders', {...});
    expect(response.status).toBe(201);
  });
});

// ✅ Contract Test (API contracts)
describe('User Service Contract', () => {
  test('should return user in expected format', async () => {
    const response = await userService.getUser(1);
    expect(response).toHaveProperty('id');
    expect(response).toHaveProperty('email');
    expect(response).toHaveProperty('name');
  });
});
```

---

## 📊 Deployment Strategies

### 1. Container Orchestration (Kubernetes)

```yaml
apiVersion: v1
kind: Namespace
metadata:
  name: ecommerce

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: user-service
  namespace: ecommerce
spec:
  replicas: 3
  selector:
    matchLabels:
      app: user-service
  template:
    metadata:
      labels:
        app: user-service
    spec:
      containers:
        - name: user-service
          image: myregistry/user-service:1.0
          ports:
            - containerPort: 3001
          env:
            - name: DB_HOST
              valueFrom:
                configMapKeyRef:
                  name: database-config
                  key: host
          resources:
            requests:
              memory: "256Mi"
              cpu: "250m"
            limits:
              memory: "512Mi"
              cpu: "500m"
          livenessProbe:
            httpGet:
              path: /health
              port: 3001
            initialDelaySeconds: 30
            periodSeconds: 10
```

---

## ✅ ตรวจสอบความเข้าใจ

**คำถามตัวเอง:**

1. ✓ Microservices vs Monolithic ต่างกันอย่างไร?
2. ✓ Database per service ทำไมสำคัญ?
3. ✓ Service discovery ทำไมต้อง?
4. ✓ Saga pattern แก้ปัญหาอะไร?
5. ✓ Circuit breaker ใช้เมื่อไร?
6. ✓ Eventual consistency คืออะไร?
7. ✓ เมื่อไดควรใช้ synchronous vs asynchronous?

---

## 📚 สรุป

### Key Takeaways

```
✅ Microservices = Independent services
✅ Database per service = Data isolation
✅ Independent deployment = Agility
✅ Technology diversity = Best tool per job
✅ Resilience patterns = System stability
✅ Complexity cost = Operational overhead
✅ Need: DevOps, monitoring, distributed systems expertise
```

### เมื่อไดควรเลือก Microservices

```
✅ USE IF:
- 50-1000+ developers
- Large projects
- Different scaling needs
- Multiple tech stacks
- Independent deployments
- Large DevOps team

❌ DON'T USE IF:
- <20 developers
- Small project
- Limited DevOps expertise
- Real-time transactions
- Low-latency critical
- Simple business logic
```

---
