Recuperación de errores: degradación elegante a escala
SchemaBridge Team · 2026-01-16 · Resilience, Error Handling, Fault Tolerance
Cómo gestionar reintentos y backoffs a escala, y cómo la resiliencia gestionada evita las "tormentas de reintentos".
Puntos clave Una lógica de reintentos ingenua amplifica una caída hasta convertirla en una tormenta de reintentos que tumba precisamente el servicio al que está martilleando. La resiliencia surge de reintentos acotados —un backoff exponencial corto para fallos HTTP transitorios y un ritmo adaptativo cuando un backend informa de sobrecarga—, además de despliegues graduales con rollback automático para las nuevas versiones de workflow y de herramientas de recuperación humana (Retry, Resolve, Start over) para todo lo que la automatización no debería decidir.
La "tormenta de reintentos": por qué falla el manejo de errores ingenuo
En los primeros tiempos de los sistemas distribuidos, "manejar errores" solía significar envolver un fragmento de código en un try/catch y quizá añadir un simple bucle while que reintentaba tres veces. Esto funciona en un entorno pequeño y aislado, donde los fallos son raros y localizados. Pero a escala, en una malla de microservicios interconectados, los reintentos ingenuos son la receta para un colapso sistémico conocido como tormenta de reintentos (Retry Storm, o "Thundering Herd").
Imagine un escenario en el que su base de datos principal se vuelve algo lenta bajo carga intensa durante unas rebajas de Black Friday. La latencia de las consultas pasa de 10 ms a 1100 ms. Su API tiene un timeout estándar de 1 segundo. De repente, mil workers concurrentes alcanzan ese timeout a la vez. Todos capturan el error y, siguiendo la lógica de su bucle sencillo, reintentan la consulta de inmediato.
Ahora su base de datos —que ya tenía dificultades para atender las 1.000 peticiones iniciales— recibe de golpe 1.000 peticiones adicionales. La carga se duplica al instante. La CPU de la base de datos se dispara al 100 % y las latencias suben a 5 segundos. Los workers vuelven a fallar y vuelven a reintentar. El sistema entra en un bucle de retroalimentación positiva de fallos. En la práctica, se ha hecho un DDoS a su propia infraestructura. Ha convertido una degradación menor del rendimiento en una caída total del sistema.
Aceptar el fallo: los errores forman parte de la API
En SchemaBridge abandonamos la idea de que los errores son "excepcionales". En un mundo orientado a eventos, el fallo es tan habitual como el éxito. Las redes se particionan, los pods se comportan de forma errática y las APIs de terceros tienen ventanas de mantenimiento. Tratamos la recuperación de errores no como un bloque catch en su código, sino como un ciclo de vida gestionado en la plataforma, con límites deliberadamente estrictos sobre lo que se reintenta automáticamente.
Cómo clasifica SchemaBridge los fallos
Para recuperarse con eficacia, primero hay que entender por qué falló algo. SchemaBridge toma la decisión en dos capas:
| Capa | Fallo | Qué ocurre automáticamente |
| :--- | :--- | :--- |
| Llamada HTTP (Gateway) | 5xx, 429 o un error de E/S (timeout, conexión reiniciada) | Se reintenta dentro del proceso, hasta 3 intentos más con backoff exponencial |
| Llamada HTTP (Gateway) | Cualquier otro 4xx (400, 401, 403, 404…) | No se reintenta: una contraseña incorrecta nunca funcionará en el segundo intento |
| Paso (vertex) | Sobrecarga transitoria de un backend con límite de tasa (external_overload) | Se vuelve a despachar automáticamente, hasta un presupuesto por vertex |
| Paso (vertex) | Todo lo demás | Terminal en el primer intento; la ejecución aparece en rojo y espera a un operador |
El comportamiento por defecto es deliberadamente conservador: el fallo de un paso es permanente salvo que se demuestre que es transitorio. Preferimos mostrar un fallo a una persona antes que volver a ejecutar en silencio un efecto secundario que podría no ser seguro repetir.
Anatomía de un reintento acotado: las matemáticas del backoff
Backoff exponencial para llamadas HTTP
Cuando una llamada de Gateway sufre un error transitorio, la plataforma no martillea el destino cada segundo. Espera exponencialmente más entre intentos.
$$Wait = Base \times 2^{Retry - 1}$$
- Falla el intento inicial
- Reintento 1: esperar 1 s
- Reintento 2: esperar 2 s
- Reintento 3: esperar 4 s
Son cuatro intentos en total, a lo largo de unos siete segundos. Si el destino responde 429 Too Many Requests con una cabecera Retry-After, la plataforma la respeta, con un tope de 30 segundos. Esta progresión corta y acotada absorbe los cortes breves de red sin convertir a un servicio en apuros en una víctima. Tenga en cuenta que el backoff no es aleatorio —no hay jitter—, así que está diseñado para suavizar un corte breve, no para coordinar miles de clientes independientes.
Re-despacho adaptativo para backends sobrecargados
Un backoff corto es la herramienta equivocada para un backend realmente saturado. En los tipos de paso con límite de tasa (pasos de Gateway y agénticos), un fallo por sobrecarga se retroalimenta en el control de admisión por destino de la plataforma, que reduce la tasa a la que admite trabajo hacia ese destino (un controlador AIMD, la misma idea que usa TCP para la congestión). Después, el paso fallido se vuelve a despachar automáticamente por esa misma vía de admisión: por defecto hasta 3 veces, configurable por vertex con maxAutoRetries (fíjelo en 0 para un paso cuyo efecto secundario nunca deba reenviarse).
{
"type": "GATEWAY",
"config": {
"url": "https://api.example.com/v1/charges",
"method": "POST",
"maxAutoRetries": 5
}
}
Como el ritmo proviene del control de admisión y no de un temporizador fijo, los reintentos se ralentizan exactamente tanto como necesita el destino. Si la sobrecarga dura más que el presupuesto, el paso falla y la ejecución espera a un operador.
Rollback gradual: seguridad en los lanzamientos de workflows
A veces los reintentos son inútiles. Si una nueva versión de workflow introduce un bug, ninguna cantidad de reintentos lo arreglará. Hay que hacer rollback.
SchemaBridge admite despliegues graduales con rollback automático para versiones de workflow, implementados como un workflow de sistema (gradual_deploy).
- Aumento progresivo: una parte configurable del tráfico (10 % por defecto, desde un mínimo del 1 %) se dirige a la nueva versión, y esa parte se incrementa paso a paso a intervalos.
- Comprobación de salud: en cada paso, una ejecución de monitorización compara el número de errores de la nueva versión con un umbral fijo. Si se supera, el despliegue devuelve el tráfico de la nueva versión al 0 %.
Esto limita el radio de impacto de un lanzamiento de workflow defectuoso a la parte del tráfico que había alcanzado cuando la comprobación lo detectó. Se aplica a versiones de workflow —no a la configuración de infraestructura— y es una red de seguridad, no una garantía: el tráfico que recibió la nueva versión antes de que saltara el umbral quedó igualmente expuesto.
Recuperación con intervención humana: la caja de herramientas del operador
Algunos fallos requieren un cerebro, no un bucle. Si un workflow falla porque una conciliación bancaria no cuadra con el importe de la factura por 0,01 $, ningún código puede ni debe decidir qué hacer.
En SchemaBridge, esa ejecución simplemente termina en FAILED, con todo lo que un operador necesita para actuar:
- Visibilidad: el paso fallido aparece marcado en rojo en el grafo de la ejecución y en el monitor.
- Análisis forense: un operador puede ver la entrada del paso, su salida y el mensaje de error (p. ej., "mismatch: 100.00 vs 100.01").
- La intervención: el operador elige la reparación adecuada:
- Retry vuelve a ejecutar el paso fallido y continúa el workflow desde ahí.
- Resolve & continue acepta el fallo, registra una salida proporcionada por el operador para ese paso y deja que el resto del workflow continúe.
- Start over vuelve a ejecutar todo el workflow como una nueva ejecución.
- Resume on new version continúa una ejecución fallida desde el punto del fallo sobre una versión corregida del workflow.
Así, los "errores" dejan de ser una fuente de pánico y de apaños en la base de datos para convertirse en un workflow operativo estándar.
Escenario ilustrativo: una caída de la pasarela de pagos
Piense en una empresa SaaS de suscripciones que procesa un gran lote de renovaciones cada medianoche. Una noche, su pasarela de pagos principal sufre una caída prolongada en una región.
La forma antigua
Un sistema heredado basado en simples cron jobs reintenta tres veces cuando la pasarela cae y luego marca las suscripciones como "Fallida / Pago rechazado". Para cuando los ingenieros se despiertan, puede que se hayan desactivado cuentas de clientes porque el sistema concluyó que sus pagos fueron rechazados, cuando en realidad la pasarela simplemente estaba caída. La cola de soporte se llena y la pérdida de clientes sigue a los correos de "Cuenta cancelada".
La forma SchemaBridge
Ahora imagine el mismo motor de facturación funcionando sobre SchemaBridge, siendo honestos.
1. Reintentos acotados: cuando empiezan los 503, cada llamada de cobro se reintenta con un backoff corto. Un corte breve se absorbe; una caída de horas no: esas ejecuciones de renovación fallan.
2. Un fallo no es una decisión: como un paso fallido detiene su ejecución en lugar de seguir por una rama de "rechazado", no se cancela la cuenta de nadie por una caída que se interpretó erróneamente como un rechazo. Las ejecuciones fallidas quedan en el monitor, en rojo, con el error de la pasarela adjunto.
3. La recuperación es una acción masiva: cuando la pasarela vuelve a estar sana, un operador selecciona las ejecuciones fallidas y las reintenta en bloque.
El resultado esperado
La caída sigue ocurriendo y alguien sigue teniendo que actuar por la mañana. Lo que cambia es el daño: sin cancelaciones erróneas, sin correos espurios y con una recuperación que es una sola acción masiva en lugar de una limpieza de la base de datos. Ese es el valor de negocio de la resiliencia.
Lista de comprobación experta para un diseño tolerante a fallos
Para construir un sistema resiliente, siga estas heurísticas:
1. Planifique cómo deshacer cada escritura: si crea un registro, sepa cómo lo eliminaría o archivaría en caso de fallo, aunque ese deshacer sea un paso que active una persona. La simetría es clave para la consistencia.
2. Añada jitter a los reintentos de los clientes que usted controla: cuando muchos clientes independientes reintentan con el mismo calendario, la aleatoriedad evita que se sincronicen en una estampida.
3. Prefiera una ejecución detenida a una rama equivocada: no deje que un fallo de infraestructura se haga pasar por un resultado de negocio. Una ejecución fallida que espera a una persona es mejor que una silenciosamente errónea.
4. Audite sus rutas de error: a menudo probamos el "camino feliz" pero ignoramos el "camino del fallo". En un entorno de staging, apunte un paso a un endpoint que devuelva 503 y 400 y confirme que la ejecución se comporta como espera en cada caso.
Conclusión: el fallo es una oportunidad para la resiliencia
La recuperación de errores no consiste en prevenir bugs; consiste en prevenir desastres. Al acotar los reintentos automáticos, dejar que la sobrecarga ralentice el sistema en lugar de desbocarlo y dar a los operadores herramientas de recuperación precisas, gana la libertad de construir integraciones complejas sin miedo a la "tormenta de reintentos".
Parte de nuestra serie Building the Bridge. Vea también: Infraestructura como workflow sobre la gestión de recursos en la nube con lógica visual.