Audiencia
Esta guía es para desarrolladores que necesitan construir integraciones confiables con APIs:
- Desarrolladores backend implementando clientes de API que necesitan manejar fallos correctamente
- Desarrolladores frontend construyendo aplicaciones que permanezcan responsivas cuando las APIs fallan
- Arquitectos de sistemas diseñando sistemas distribuidos resilientes
- Ingenieros DevOps entendiendo patrones de fallo para mejorar monitoreo y alertas
- Cualquiera que haya experimentado frustración con APIs que expiran, devuelven errores o se vuelven inaccesibles
Debes estar familiarizado con los conceptos básicos de HTTP. Si no, comienza con HTTP para APIs REST.
Objetivo
Después de leer esta guía, entenderás:
- Por qué fallan las APIs y las diferentes categorías de fallos
- Qué son los timeouts y por qué son críticos para la salud del sistema
- Cómo funcionan las estrategias de reintento, incluyendo backoff exponencial y jitter
- Por qué importa la idempotencia y cómo las claves de idempotencia previenen duplicados
- Cómo el patrón circuit breaker protege tu sistema de fallos en cascada
- Qué significa la degradación elegante y cuándo aplicarla
No estarás configurando patrones de resiliencia listos para producción todavía, pero tendrás un modelo mental sólido de cómo los sistemas resilientes manejan los fallos.
1. Por Qué Fallan las APIs
Las APIs fallan. No ocasionalmente—constantemente. Entender los modos de fallo es el primer paso para construir sistemas resilientes.
Categorías de Fallos
Los fallos de API caen en categorías distintas, cada una requiriendo un manejo diferente:
graph TD
F[Fallo de API] --> N[Fallos de Red]
F --> T[Fallos de Timeout]
F --> O[Fallos de Sobrecarga]
F --> B[Fallos por Bugs]
F --> D[Fallos de Dependencias]
N --> N1[Conexión rechazada]
N --> N2[Resolución DNS fallida]
N --> N3[Handshake TLS fallido]
T --> T1[Timeout de lectura]
T --> T2[Timeout de conexión]
T --> T3[Timeout de inactividad]
O --> O1[Rate limiting - 429]
O --> O2[Servidor sobrecargado - 503]
O --> O3[Cola llena]
B --> B1[Error del servidor - 500]
B --> B2[Respuesta inesperada]
B --> B3[Corrupción de datos]
D --> D1[Base de datos caída]
D --> D2[API externa falló]
D --> D3[Cola de mensajes inaccesible]
style F fill:#ffccbc
style N fill:#fff9c4
style T fill:#fff9c4
style O fill:#fff9c4
style B fill:#fff9c4
style D fill:#fff9c4Fallos de Red
La red entre tu cliente y la API puede fallar de muchas formas:
- Conexión rechazada: El servidor no está aceptando conexiones
- Fallo de DNS: No puede resolver el hostname a una dirección IP
- Errores TLS: Certificado expirado, hostname no coincide, incompatibilidad de protocolo
- Conexión reiniciada: La conexión fue cerrada forzosamente
- Pérdida de paquetes: Los datos nunca llegan o se corrompen en tránsito
Los fallos de red son usualmente transitorios—se resuelven solos cuando la red se recupera.
Fallos de Timeout
Los timeouts ocurren cuando algo toma demasiado tiempo:
- Timeout de conexión: Establecer la conexión TCP toma demasiado tiempo
- Timeout de lectura: Esperar los datos de respuesta toma demasiado tiempo
- Timeout de inactividad: La conexión estuvo sin uso demasiado tiempo
Los timeouts son ambiguos: ¿La petición tuvo éxito? Enviaste la petición, pero no sabes si el servidor la recibió, la procesó, o envió una respuesta que se perdió.
Fallos de Sobrecarga
Los servidores pueden verse abrumados:
- Rate limiting (429): Estás enviando peticiones demasiado rápido
- Servidor sobrecargado (503): El servidor no puede manejar la carga actual
- Cola llena: Las colas de peticiones están saturadas
Los fallos de sobrecarga señalan: “Estoy muy ocupado, intenta más tarde.”
Fallos por Bugs
A veces el servidor mismo está roto:
- 500 Internal Server Error: Excepción no manejada, puntero nulo, etc.
- Formato de respuesta inesperado: La API cambió sin aviso
- Errores de lógica: El servidor procesó la petición incorrectamente
Los fallos por bugs frecuentemente requieren intervención humana para arreglarlos.
Fallos de Dependencias
Las APIs modernas dependen de otros servicios:
- Base de datos no disponible: No puede almacenar o recuperar datos
- API externa falló: El servicio de terceros está caído
- Fallo de caché: Redis/Memcached no disponible
Los fallos de dependencias se propagan en cascada—un servicio fallando puede tumbar muchos otros.
La Realidad del Fallo
En un sistema distribuido con múltiples servicios, los fallos son inevitables. Si cada servicio tiene 99.9% de uptime, una petición que toca 10 servicios tiene solo 99%^10 = 99% de tasa de éxito—1% de las peticiones fallan incluso cuando todo es “confiable.”
Construir sistemas resilientes significa aceptar que los fallos ocurren y diseñar para ellos.
2. Timeouts: Tu Primera Línea de Defensa
Un timeout es un límite de cuánto tiempo esperarás a que algo se complete. Sin timeouts, una API lenta o sin respuesta puede colgar toda tu aplicación.
Por Qué Importan los Timeouts
Imagina una API de pagos que se vuelve lenta. Sin timeouts:
sequenceDiagram
participant C as Tu App
participant P as API de Pagos
C->>P: Procesar pago
Note over P: API lenta...
Note over C: Thread bloqueado
esperando para siempre
Note over P: Aún procesando...
Note over C: Más peticiones llegan
Todos los threads bloqueados
Note over P: Más tiempo pasa...
Note over C: Pool de threads agotado
Aplicación colgada
style C fill:#ffccbcUna dependencia lenta puede consumir todos tus recursos, haciendo que toda tu aplicación no responda. Esto se llama agotamiento de recursos.
Tipos de Timeouts
Timeout de conexión: Cuánto tiempo esperar al establecer una conexión.
- Muy corto: Falla antes de que la conexión se complete en redes lentas
- Muy largo: Recursos atados esperando servidores inalcanzables
- Valores típicos: 1-10 segundos
Timeout de lectura (timeout de respuesta): Cuánto tiempo esperar datos de respuesta después de conectar.
- Muy corto: Falla en operaciones legítimamente lentas
- Muy largo: Recursos atados esperando servidores trabados
- Valores típicos: 5-60 segundos (depende de la operación)
Timeout total: Tiempo máximo para todo el ciclo petición-respuesta.
- Asegura tiempo de espera acotado sin importar los reintentos
- Valores típicos: 30-120 segundos
El Dilema del Timeout
Configurar timeouts involucra compromisos:
| Timeout Muy Corto | Timeout Muy Largo |
|---|---|
| Falla peticiones legítimas | Fallos lentos |
| Alta tasa de errores | Agotamiento de recursos |
| Mala experiencia de usuario | Lentitud en cascada |
La idea clave: Un fallo rápido frecuentemente es mejor que un éxito lento. Tus usuarios preferirían ver “intenta de nuevo” que esperar para siempre.
Timeout como Contrato
Piensa en los timeouts como un contrato con tus usuarios: “Prometo responder dentro de X segundos, aunque la respuesta sea ‘No lo sé.’”
# Petición con contexto de timeout
POST /payments HTTP/1.1
X-Request-Timeout: 30
# El servidor debería abortar si no puede responder a tiempo
Sin este contrato, el tiempo de respuesta de tu aplicación está determinado por tu dependencia más lenta—que podría ser infinitamente lenta.
3. Estrategias de Reintento: Cuándo y Cómo Intentar de Nuevo
Los reintentos pueden convertir fallos transitorios en peticiones exitosas. Pero reintentos ingenuos pueden empeorar las cosas.
Cuándo Reintentar
No todos los fallos deberían reintentarse:
flowchart TD
E[Ocurrió Error] --> S{Código de Estado?}
S -->|4xx| C4[Error del Cliente]
S -->|5xx| C5[Error del Servidor]
S -->|Error de Red| CN[Error de Red]
S -->|Timeout| CT[Timeout]
C4 --> D4{Cuál 4xx?}
D4 -->|400, 401, 403, 404| N1[No Reintentar
Arregla la petición]
D4 -->|429| R1[Reintentar
Después de esperar]
D4 -->|408| R2[Reintentar
Inmediatamente posible]
C5 --> D5{Cuál 5xx?}
D5 -->|500| M1[Quizás Reintentar
Bug del servidor?]
D5 -->|502, 503, 504| R3[Reintentar
Fallo transitorio]
CN --> R4[Reintentar
Red recuperada?]
CT --> R5[Reintentar
Pero con cuidado!]
style N1 fill:#ffccbc
style R1 fill:#c8e6c9
style R2 fill:#c8e6c9
style R3 fill:#c8e6c9
style R4 fill:#c8e6c9
style R5 fill:#fff9c4
style M1 fill:#fff9c4Seguro para reintentar:
- 429 Too Many Requests (después de esperar)
- 502 Bad Gateway
- 503 Service Unavailable
- 504 Gateway Timeout
- Errores de red (conexión rechazada, fallo DNS)
- Timeouts (con precaución)
No reintentar:
- 400 Bad Request (tu petición está mal formada)
- 401 Unauthorized (tus credenciales están mal)
- 403 Forbidden (no tienes permiso)
- 404 Not Found (el recurso no existe)
- 409 Conflict (conflicto de estado, necesita resolución)
Quizás reintentar:
- 500 Internal Server Error (podría ser un bug transitorio)
- Timeouts en operaciones no idempotentes (ver sección de idempotencia)
El Problema con Reintentos Ingenuos
Reintentos inmediatos simples pueden causar tormentas de reintentos:
sequenceDiagram
participant C1 as Cliente 1
participant C2 as Cliente 2
participant C3 as Cliente 3
participant S as Servidor Sobrecargado
Note over S: Servidor al 100% de capacidad
C1->>S: Petición 1
C2->>S: Petición 2
C3->>S: Petición 3
S--xC1: 503 Service Unavailable
S--xC2: 503 Service Unavailable
S--xC3: 503 Service Unavailable
Note over C1,C3: Todos los clientes reintentan inmediatamente
C1->>S: Reintento 1
C2->>S: Reintento 2
C3->>S: Reintento 3
Note over S: Ahora manejando 6 peticiones
en lugar de 3!
style S fill:#ffccbcCuando todos los clientes reintentan inmediatamente, amplifican la carga en un servidor que ya está luchando.
Backoff Exponencial
La solución es backoff exponencial: Esperar más tiempo entre cada reintento.
Intento 1: Esperar 1 segundo
Intento 2: Esperar 2 segundos
Intento 3: Esperar 4 segundos
Intento 4: Esperar 8 segundos
Intento 5: Esperar 16 segundos
...
La espera crece exponencialmente: delay = base * 2^intento
graph LR
A1[Intento 1] -->|1s espera| A2[Intento 2]
A2 -->|2s espera| A3[Intento 3]
A3 -->|4s espera| A4[Intento 4]
A4 -->|8s espera| A5[Intento 5]
style A1 fill:#e3f2fd
style A2 fill:#bbdefb
style A3 fill:#90caf9
style A4 fill:#64b5f6
style A5 fill:#42a5f5Esto le da tiempo al servidor para recuperarse mientras previene tormentas de reintentos.
Jitter: Aleatorizando las Esperas
Incluso con backoff exponencial, si 1000 clientes empiezan a reintentar al mismo tiempo, golpearán al servidor en oleadas sincronizadas.
Jitter añade aleatoriedad a la espera:
# Full jitter (recomendado)
delay = random(0, base * 2^intento)
# Decorrelated jitter
delay = random(base, delay_anterior * 3)
En lugar de que todos los clientes esperen exactamente 4 segundos, esperan aleatoriamente entre 0-4 segundos, distribuyendo la carga:
graph LR
subgraph Sin Jitter
W1[Cliente A: 4s]
W2[Cliente B: 4s]
W3[Cliente C: 4s]
end
subgraph Con Jitter
J1[Cliente A: 1.2s]
J2[Cliente B: 3.7s]
J3[Cliente C: 2.4s]
end
style W1 fill:#ffccbc
style W2 fill:#ffccbc
style W3 fill:#ffccbc
style J1 fill:#c8e6c9
style J2 fill:#c8e6c9
style J3 fill:#c8e6c9Cuándo NO Reintentar
Nunca reintentar cuando:
- La petición tuvo éxito (obviamente, pero verifica idempotencia)
- El error es permanente: 400, 401, 403, 404
- Has excedido el máximo de reintentos: Saber cuándo rendirse
- El timeout ha expirado: No reintentar hasta el infinito
- La operación no es segura de repetir: Operaciones no idempotentes sin claves de idempotencia
Ten cuidado cuando:
- La operación tiene efectos secundarios: Podría causar duplicados
- El timeout fue ambiguo: ¿Tuvo éxito o no?
- Estás propagando latencia al usuario: Ellos están esperando
Presupuesto de Reintentos
Establece límites en los reintentos para prevenir bucles infinitos:
- Máximo de intentos: Limita el total de intentos (ej: 3-5)
- Tiempo total máximo: Deja de reintentar después de N segundos
- Presupuesto de reintentos: Solo reintentar X% de las peticiones en una ventana de tiempo
4. Idempotencia: Haciendo los Reintentos Seguros
Ocurre un timeout. ¿Tu pago pasó? No lo sabes. Si reintentas y ya tuvo éxito, podrías cobrarle al cliente dos veces.
La idempotencia hace que las operaciones sean seguras de reintentar.
Qué Es la Idempotencia
Una operación es idempotente si llamarla múltiples veces produce el mismo resultado que llamarla una vez.
graph LR
subgraph Idempotente
I1[x = 5] -->|Llamar una vez| IR1[x = 5]
I2[x = 5] -->|Llamar dos veces| IR2[x = 5]
I3[x = 5] -->|Llamar N veces| IR3[x = 5]
end
subgraph No Idempotente
N1[x = 0] -->|Llamar una vez| NR1[x = 1]
N2[x = 0] -->|Llamar dos veces| NR2[x = 2]
N3[x = 0] -->|Llamar N veces| NR3[x = N]
end
style IR1 fill:#c8e6c9
style IR2 fill:#c8e6c9
style IR3 fill:#c8e6c9
style NR1 fill:#fff9c4
style NR2 fill:#fff9c4
style NR3 fill:#ffccbcOperaciones naturalmente idempotentes:
GET /users/123— Leer no cambia nadaPUT /users/123 {name: "Alice"}— Establece el mismo estado cada vezDELETE /users/123— El recurso ya no existe después de la primera llamada
NO naturalmente idempotentes:
POST /payments— Cada llamada podría crear un nuevo pagoPOST /emails/send— Cada llamada podría enviar otro emailx = x + 1— Cada llamada incrementa
Claves de Idempotencia
Para operaciones no idempotentes, usa claves de idempotencia—identificadores únicos que permiten al servidor detectar peticiones duplicadas.
POST /payments HTTP/1.1
Content-Type: application/json
Idempotency-Key: abc123-unique-request-id
{
"amount": 100,
"currency": "USD",
"recipient": "user_456"
}
Cómo funciona:
sequenceDiagram
participant C as Cliente
participant S as Servidor
participant DB as Base de Datos
C->>S: POST /payments
Idempotency-Key: abc123
S->>DB: Verificar: visto abc123?
DB-->>S: No
S->>DB: Procesar pago
S->>DB: Almacenar: abc123 -> resultado
S-->>C: 200 OK, payment_id: 789
Note over C: Red falla, cliente reintenta
C->>S: POST /payments
Idempotency-Key: abc123
S->>DB: Verificar: visto abc123?
DB-->>S: Sí, resultado existe
S-->>C: 200 OK, payment_id: 789
Note over C: Mismo resultado, sin pago duplicado!Propiedades clave de las claves de idempotencia:
- Generadas por el cliente: El cliente crea un ID único antes del primer intento
- Almacenadas por el servidor: El servidor recuerda el mapeo clave -> resultado
- Devuelve resultado cacheado: En el reintento, el servidor devuelve la respuesta original
- Expira eventualmente: Las claves no necesitan vivir para siempre (horas a días)
El Contrato de Idempotencia
Cuando usas una clave de idempotencia:
- Misma clave + misma petición = mismo resultado
- Misma clave + diferente petición = error (algunas APIs permiten esto, otras no)
- El servidor debe completar el almacenamiento antes de responder (o usar transacciones)
Error común: Generar una nueva clave de idempotencia para cada reintento. Eso derrota el propósito—cada reintento parece una nueva petición!
// MAL: Nueva clave para cada intento
async function processPaymentMal(amount) {
for (let attempt = 0; attempt < 3; attempt++) {
try {
const idempotencyKey = generateUUID(); // Nueva clave cada vez!
return await api.createPayment({ amount, idempotencyKey });
} catch (error) {
if (attempt === 2) throw error;
}
}
}
// BIEN: Misma clave para todos los intentos
async function processPaymentBien(amount) {
const idempotencyKey = generateUUID(); // Generar una vez
for (let attempt = 0; attempt < 3; attempt++) {
try {
return await api.createPayment({ amount, idempotencyKey });
} catch (error) {
if (attempt === 2) throw error;
}
}
}
5. Circuit Breaker: Protegiendo Tu Sistema
Cuando una dependencia está fallando, continuar llamándola desperdicia recursos y puede causar fallos en cascada. El patrón circuit breaker detiene esto.
La Analogía del Circuit Breaker
Piensa en un interruptor de circuito eléctrico en tu casa:
- Operación normal: La electricidad fluye libremente
- Sobrecarga detectada: El interruptor salta, corta la energía
- Reset manual: Después de arreglar el problema, reseteas el interruptor
Un circuit breaker de API funciona de la misma manera:
- Estado cerrado: Las peticiones pasan normalmente
- Estado abierto: Las peticiones fallan inmediatamente sin llamar al servicio fallando
- Estado semi-abierto: Permite algunas peticiones de prueba para verificar si el servicio se recuperó
Estados del Circuit Breaker
stateDiagram-v2
[*] --> Cerrado
Cerrado --> Abierto: Umbral de fallos excedido
Abierto --> SemiAbierto: Timeout expira
SemiAbierto --> Cerrado: Petición de prueba exitosa
SemiAbierto --> Abierto: Petición de prueba falla
note right of Cerrado
Operación normal
Contando fallos
end note
note right of Abierto
Fallo rápido
Sin peticiones enviadas
end note
note right of SemiAbierto
Probando recuperación
Peticiones limitadas
end noteCómo Funciona
Estado Cerrado (normal):
sequenceDiagram
participant C as Cliente
participant CB as Circuit Breaker
participant S as Servicio
C->>CB: Petición 1
CB->>S: Reenviar petición
S-->>CB: Éxito
CB-->>C: Éxito
C->>CB: Petición 2
CB->>S: Reenviar petición
S--xCB: Fallo (1)
CB-->>C: Fallo
C->>CB: Petición 3
CB->>S: Reenviar petición
S--xCB: Fallo (2)
CB-->>C: Fallo
Note over CB: Conteo de fallos: 2/5Las peticiones pasan. Los fallos se cuentan. Si los fallos exceden el umbral (ej: 5 fallos en 30 segundos), el circuito se abre.
Estado Abierto (fallando rápido):
sequenceDiagram
participant C as Cliente
participant CB as Circuit Breaker
participant S as Servicio
Note over CB: Circuito ABIERTO
Servicio asumido caído
C->>CB: Petición 1
CB--xC: Falla inmediatamente
Note over CB: Sin petición enviada!
C->>CB: Petición 2
CB--xC: Falla inmediatamente
C->>CB: Petición 3
CB--xC: Falla inmediatamente
Note over CB: Esperando timeout...Ninguna petición llega al servicio fallando. Los clientes obtienen fallos rápidos en lugar de timeouts lentos. El sistema ahorra recursos y evita amplificar el problema.
Estado Semi-Abierto (probando recuperación):
sequenceDiagram
participant C as Cliente
participant CB as Circuit Breaker
participant S as Servicio
Note over CB: Timeout expirado
Intentar semi-abierto
C->>CB: Petición 1
CB->>S: Petición de prueba
S-->>CB: Éxito!
CB-->>C: Éxito
Note over CB: Servicio recuperado!
Circuito CERRADODespués de un timeout (ej: 30 segundos), el circuit breaker permite una petición de prueba. Si tiene éxito, el circuito se cierra. Si falla, el circuito se abre de nuevo.
Por Qué Importan los Circuit Breakers
Sin un circuit breaker:
graph LR
subgraph Sin Circuit Breaker
A[Tu Servicio] -->|100 req/s| B[Servicio Fallando]
B -->|100 timeouts/s| A
A -->|Threads agotados| C[Tu Servicio Caído]
end
style B fill:#ffccbc
style C fill:#ffccbcCon un circuit breaker:
graph LR
subgraph Con Circuit Breaker
A[Tu Servicio] -->|Circuito Abierto| CB[Circuit Breaker]
CB -->|Fallo Rápido| A
A -->|Degrada elegantemente| D[Tu Servicio Sigue Arriba]
end
style D fill:#c8e6c9Beneficios:
- Fallo rápido: No desperdiciar tiempo en peticiones condenadas
- Proteger recursos: No agotar pools de threads/conexiones
- Permitir recuperación: Dar al servicio fallando espacio para respirar
- Prevenir fallos en cascada: Tu fallo no se convierte en el fallo de todos
Configuración del Circuit Breaker
Parámetros clave:
| Parámetro | Descripción | Valor Típico |
|---|---|---|
| Umbral de fallos | Fallos para abrir circuito | 5-10 fallos |
| Ventana de tiempo | Período para contar fallos | 30-60 segundos |
| Timeout abierto | Cuánto tiempo permanece abierto | 30-60 segundos |
| Peticiones semi-abiertas | Peticiones de prueba permitidas | 1-3 |
6. Degradación Elegante: Fallando Bien
Cuando una dependencia falla, tienes opciones más allá de “error” o “éxito.” Degradación elegante significa proporcionar funcionalidad reducida en lugar de fallo completo.
Estrategias de Degradación
Devolver datos cacheados:
Cuando la API de productos está caída, devolver datos cacheados obsoletos con una advertencia.
{
"products": [...],
"metadata": {
"cached": true,
"cachedAt": "2026-01-12T10:00:00Z",
"warning": "Los datos pueden estar desactualizados"
}
}
Devolver valores por defecto:
Cuando el servicio de personalización está caído, mostrar recomendaciones genéricas.
{
"recommendations": ["popular-item-1", "popular-item-2"],
"personalized": false
}
Reducir funcionalidad:
Cuando el procesamiento de pagos está lento, deshabilitar checkout pero mantener la navegación funcionando.
Encolar para después:
Cuando el servicio de email está caído, encolar emails y enviarlos cuando el servicio se recupere.
Árbol de Decisión de Degradación
flowchart TD
F[Dependencia Falló] --> Q1{Crítico para
esta operación?}
Q1 -->|No| S1[Omitirlo
Continuar sin él]
Q1 -->|Sí| Q2{Tienes datos cacheados?}
Q2 -->|Sí| S2[Devolver cacheado
con advertencia]
Q2 -->|No| Q3{Tienes valor por defecto?}
Q3 -->|Sí| S3[Devolver por defecto
con advertencia]
Q3 -->|No| Q4{Puedes encolar para después?}
Q4 -->|Sí| S4[Encolar y
confirmar recepción]
Q4 -->|No| S5[Devolver error
elegantemente]
style S1 fill:#c8e6c9
style S2 fill:#c8e6c9
style S3 fill:#fff9c4
style S4 fill:#fff9c4
style S5 fill:#ffccbcEjemplos de Degradación Elegante
Sitio de e-commerce:
| Característica | Estado Degradado | Experiencia de Usuario |
|---|---|---|
| Búsqueda de productos | Mostrar resultados cacheados | “Los resultados pueden estar desactualizados” |
| Recomendaciones | Mostrar items populares | Menos personalizado pero funcional |
| Reseñas | Ocultar sección de reseñas | Página de producto aún funciona |
| Pago | Mostrar “intenta más tarde” | No puede comprar, pero puede navegar |
Red social:
| Característica | Estado Degradado | Experiencia de Usuario |
|---|---|---|
| Timeline | Mostrar posts cacheados | “Mostrando posts recientes” |
| Contador de likes | Ocultar contadores | Aún puede dar like |
| Comentarios | Deshabilitar nuevos comentarios | Puede leer existentes |
| Notificaciones | Agrupar y retrasar | Pequeño retraso aceptable |
El Principio Clave
Siempre pregunta: “¿Cuál es la mejor experiencia que puedo proporcionar cuando esto falla?”
La respuesta raramente es “mostrar una página de error.” Usualmente hay una experiencia parcial que es mejor que nada.
7. Juntando Todo
Así es como estos conceptos funcionan juntos en un sistema resiliente:
flowchart TD
R[Petición] --> T{Timeout
configurado?}
T -->|No| WARN[Agregar timeout!]
T -->|Sí| CB{Estado del
circuit breaker?}
CB -->|Abierto| FF[Fallo rápido]
CB -->|Cerrado/Semi-Abierto| S[Enviar petición]
S --> RESULT{Resultado?}
RESULT -->|Éxito| REC[Registrar éxito]
RESULT -->|Fallo| CHK{Reintentar?}
CHK -->|No| FINAL[Devolver error]
CHK -->|Sí| IK{Idempotente/
tiene clave?}
IK -->|No| DANGER[Peligroso reintentar!]
IK -->|Sí| LIMIT{Bajo límite
de reintentos?}
LIMIT -->|No| GIVEUP[Rendirse]
LIMIT -->|Sí| WAIT[Backoff + jitter]
WAIT --> CB
REC --> CLOSE[Circuito permanece/se cierra]
FINAL --> COUNT[Contar fallo]
COUNT --> THRESH{Umbral
excedido?}
THRESH -->|Sí| OPEN[Abrir circuito]
THRESH -->|No| DONE[Listo]
FF --> DEGRADE{Puede degradar
elegantemente?}
DEGRADE -->|Sí| CACHED[Devolver cacheado/defecto]
DEGRADE -->|No| ERROR[Devolver error]
style WARN fill:#ffccbc
style DANGER fill:#ffccbc
style FF fill:#fff9c4
style CACHED fill:#c8e6c9Resumen de Patrones de Resiliencia
| Problema | Solución | Concepto Clave |
|---|---|---|
| Respuestas lentas | Timeouts | Tiempo de espera acotado |
| Fallos transitorios | Reintentos | Intentar de nuevo |
| Tormentas de reintentos | Backoff exponencial | Esperar más cada vez |
| Reintentos sincronizados | Jitter | Aleatorizar esperas |
| Operaciones duplicadas | Claves de idempotencia | Misma entrada = misma salida |
| Fallos en cascada | Circuit breaker | Fallo rápido cuando dependencia caída |
| Fallo total | Degradación elegante | Mejor experiencia posible |
Qué Sigue
Esta guía cubrió los conceptos de resiliencia—entender por qué las cosas fallan y los patrones que ayudan.
Para detalles de implementación incluyendo:
- Configuración de timeouts para diferentes escenarios
- Ajuste de parámetros de reintentos para tu caso de uso
- Implementación de almacenamiento de claves de idempotencia
- Configuración de umbrales de circuit breaker
- Métricas, alertas y observabilidad para fallos
Consulta el próximo curso: Resiliencia y tolerancia a fallos en APIs REST.
Términos Relacionados del Vocabulario
Profundiza tu entendimiento con estos conceptos relacionados:
- Circuit Breaker - Patrón para manejar dependencias fallando
- Idempotencia - Haciendo operaciones seguras de reintentar
- Retry - Estrategias para intentar de nuevo
- Timeout - Acotando tiempo de espera para operaciones
- Manejo de Errores - Patrones para manejar errores de API
- Backoff - Retrasando reintentos apropiadamente
- Rate Limiting - Entendiendo respuestas 429
- Códigos de Estado 5xx - Respuestas de error del servidor
- 429 Too Many Requests - Límite de tasa excedido