---
name: microservicios
description: Arquitectura de microservicios. Cuándo usar y cuándo NO. Circuit breakers, service mesh, API gateway, saga pattern, event sourcing, CQRS, distributed tracing, health checks, service discovery. Anti-patrones.
version: "1.0.0"
herramientasPermitidas: [Read, Grep]
exclusiones:
  - "No cargar para implementación de APIs REST o GraphQL individuales — para implementación de endpoints cargar `fastapi-experto`, `api-rest-diseno` o `graphql-experto`."
  - "No cargar para infraestructura de Kubernetes, Docker o Terraform — para infra cargar `cloud-infra`."
  - "No cargar para messaging/event streaming específico (Kafka, RabbitMQ) — este skill cubre los patrones de arquitectura; para implementación de brokers usar los recursos de infra."
  - "No cargar para monolitos modulares o arquitectura hexagonal sin distribución — este skill asume distribución de red entre servicios."
evolvable: true  # default para skill estandar
---
# Arquitectura de Microservicios

## Cuándo NO cargar

- La tarea es implementar endpoints REST o GraphQL individuales dentro de un servicio — cargar `fastapi-experto`, `api-rest-diseno` o `graphql-experto`.
- El trabajo es infraestructura: Kubernetes, Docker Compose, Terraform — cargar `cloud-infra`.
- La pregunta es sobre configuración específica de un broker de mensajes (Kafka, RabbitMQ, SQS) — este skill cubre los patrones de arquitectura, no la implementación del broker.
- El sistema es un monolito modular o arquitectura hexagonal sin distribución de red — este skill asume que los servicios se comunican por red.

Microservicios no es la respuesta por defecto — es una decisión de arquitectura con
costos reales. Este skill cubre cuándo aplicarlos, cómo implementarlos y cuándo evitarlos.

---

## 1. Microservicios o Monolito — Decide primero

### Señales de que el MONOLITO es la respuesta correcta

- Equipo < 10 desarrolladores
- Dominio de negocio no bien definido aún
- Producto en fase de descubrimiento (pivots frecuentes)
- No hay equipos independientes que puedan ser dueños de servicios distintos
- Sin infraestructura de observabilidad madura
- SLA de < 99.9%

### Señales de que microservicios SUMAN valor

- Equipos independientes que necesitan deployar sin coordinación
- Módulos con requerimientos de escalado MUY distintos
- Diferentes requerimientos de seguridad o cumplimiento por módulo
- Módulos que necesitan tecnologías distintas (Python para ML, Go para performance)
- Más de 100 deploys por mes

---

## 2. Principios de Diseño de Servicios

### Bounded Context — Límites claros entre servicios

```
MONOLITO MODULAR (recomendado para empezar):
+-- modulo: empleados/
+-- modulo: nomina/
+-- modulo: asistencia/
+-- modulo: reportes/

MICROSERVICIOS (cuando los módulos necesitan escalar independientemente):
+-- servicio-empleados     — equipo A, escala: bajo
+-- servicio-nomina        — equipo B, escala: muy alto en quincena
+-- servicio-asistencia    — equipo C, escala: alto en horario laboral
+-- servicio-reportes      — equipo D, escala: bajo, alto en auditorías
```

### High Cohesion, Loose Coupling

```python
# MAL: servicio que hace demasiado (god service)
class ServicioRRHH:
    def crear_empleado(self): ...
    def calcular_nomina(self): ...
    def registrar_asistencia(self): ...

# BIEN: servicios con responsabilidad única
class ServicioEmpleados:
    def crear(self): ...
    def actualizar(self): ...
    def buscar(self): ...
```

---

## 3. Reglas Obligatorias

1. **Cada servicio tiene su propia BD** — NUNCA compartir esquemas entre servicios.
2. **SIEMPRE implementar circuit breaker** para llamadas a otros servicios.
3. **SIEMPRE propagar `X-Correlation-ID`** en todas las llamadas salientes.
4. **SIEMPRE poner timeout** en TODAS las llamadas HTTP salientes.
5. **SIEMPRE implementar idempotency** en operaciones de escritura.
6. **Exponer health checks**: `/health/live`, `/health/ready`, `/health/startup`.
7. **Logs estructurados (JSON)** con nivel, servicio y correlationId.

---

## 4. Anti-patrones Críticos

### Monolito Distribuido (el peor anti-patrón)

```
Síntomas:
- Los servicios se llaman síncronamente en cadena para cada request
- Deploy de un servicio requiere deploy de otros (acoplamiento)
- Un fallo en el servicio A causa fallo en cascada a B, C, D
- La "base de datos compartida" entre servicios

MAL:
Request -> API Gateway -> ServicioA -> ServicioB -> ServicioC -> BD compartida

BIEN:
Request -> API Gateway -> ServicioA (BD propia)
                       -> (evento async) -> ServicioB (BD propia)
```

### Otros Anti-patrones

| Anti-patrón | Problema | Solución |
|-------------|---------|---------|
| Chatty services (100s de llamadas síncronas) | Latencia acumulada | Agregar datos en el servicio o usar eventos |
| Compartir BD entre servicios | Acoplamiento fuerte | Una BD por servicio |
| Servicios demasiado pequeños (nanoservices) | Overhead operativo excesivo | Bounded context adecuado |
| Sin contrato de API versionado | Romper clientes al actualizar | Versioning en URL (/v1/, /v2/) |
| Logging sin correlation ID | Imposible tracing | `X-Correlation-ID` en headers |
| Sin idempotency en APIs | Doble procesamiento en reintentos | Idempotency keys en mutaciones |

---

## 5. Checklist de Microservicio Nuevo

- [ ] Tiene su propia BD (sin compartir esquemas con otros servicios)
- [ ] Expone `/health/live`, `/health/ready`, `/health/startup`
- [ ] Implementa circuit breaker para llamadas a otros servicios
- [ ] Propaga `X-Correlation-ID` en todas las llamadas salientes
- [ ] Tiene contrato de API documentado (OpenAPI spec)
- [ ] Versioning en URL (`/api/v1/...`)
- [ ] Idempotency implementada en operaciones de escritura
- [ ] Rate limiting configurado en el API Gateway
- [ ] Timeout configurado en TODAS las llamadas HTTP salientes
- [ ] Logs estructurados (JSON) con nivel, servicio, correlationId
- [ ] Métricas de negocio expuestas (Prometheus)
- [ ] Fallback o degradación elegante cuando dependencias fallan

---

Para ejemplos completos de API Gateway (NGINX), Circuit Breaker, Saga Pattern, Distributed Tracing (OpenTelemetry), Health Checks y Service Discovery (Consul), ver [recursos/patrones-y-ejemplos-completos.md](recursos/patrones-y-ejemplos-completos.md).

## Gotchas / Errores comunes no obvios

**Circuit breaker con estado en memoria del proceso no funciona en entornos multi-instancia**: si el circuit breaker abre en una instancia del servicio (por fallos detectados localmente), las otras instancias siguen enviando tráfico al servicio caído. Causa: el estado del circuit breaker en memoria es local al proceso. Fix: usar un circuit breaker respaldado por Redis o un service mesh (Istio, Linkerd) que administra el estado de circuit breaking a nivel de red, compartido entre todas las instancias.

**Saga con compensación no es equivalente a rollback de base de datos — los efectos secundarios ya ocurrieron**: en una Saga coreografada donde el paso 3 (envío de email) falla, la compensación no "no envía el email" — el email ya se envió en paso 1. La compensación solo puede enviar otro email que diga "la operación fue cancelada". Causa: la Saga es eventual y los pasos intermedios son commits locales irreversibles. Fix: diseñar las compensaciones como acciones de negocio válidas (no rollbacks), documentar explícitamente qué efectos no son compensables (emails enviados, notificaciones push) y diseñar el flujo de negocio para tolerar esos efectos.

**`X-Correlation-ID` propagado solo en llamadas HTTP se pierde cuando el flujo pasa por un queue (RabbitMQ, Kafka)**: si el servicio A llama al servicio B por HTTP con correlation ID y B publica un evento en Kafka sin incluir el correlation ID en el header del mensaje, el servicio C que consume el evento no puede correlacionar la traza. Causa: los mensajes async no propagan headers HTTP automáticamente. Fix: incluir el correlation ID en el payload del mensaje (o en los headers del mensaje de Kafka/RabbitMQ) como parte del contrato del evento, y extraerlo al crear el span de OpenTelemetry al consumir.

**El health check `/health/ready` que verifica la conexión a la BD puede causar restart en cascada**: si `/health/ready` falla cuando la BD tiene alta latencia (no caída), Kubernetes puede marcar el pod como unhealthy y reiniciarlo — pero el restart no resuelve el problema de latencia de BD y puede generar una cascada de reinicios. Causa: usar el health check de readiness para métricas de performance, no solo de disponibilidad. Fix: `/health/ready` debe verificar solo si el servicio puede aceptar tráfico (conexión básica a BD disponible), no la latencia — las métricas de performance van en el health de Prometheus/métricas, no en el readiness probe.
