Efectos ya aplicados cuando el proceso falla a la mitad
Se descontó el cupón, se mandó el correo y después falló la confirmación. En el cliente no hay transacciones, así que el orden de las operaciones y qué se puede deshacer se vuelven una decisión de diseño.
Un flujo con cuatro pasos: validar, reservar, cobrar, confirmar. El tercero falla. Los dos primeros ya pasaron y dejaron efectos en el mundo: una reserva tomada, un cupón consumido, quizá un correo enviado.
En una base de datos esto se resuelve con una transacción. En un flujo repartido entre el cliente, varios servicios y un proveedor externo, no hay transacción: hay que decidir a mano qué pasa con lo que ya ocurrió.
Cómo se ve en una review
| El código | El problema que esconde |
|---|---|
| Un `try` que envuelve cuatro llamadas y un solo `catch` que muestra un error genérico | No se sabe cuál falló ni qué quedó aplicado |
| El estado local se actualiza antes de que el servidor confirme | La pantalla muestra algo que no pasó |
| Un reintento sobre una operación que no es idempotente | Doble cobro, doble reserva, doble correo |
| Efectos irreversibles al principio del flujo | Cuando algo falla, ya no hay forma de volver atrás |
El más común es el segundo, con nombre propio: la actualización optimista de la interfaz. Está bien —hace que la aplicación se sienta rápida— siempre que exista el camino de revertir cuando el servidor rechaza, y ese camino es justo el que falta.
El orden importa más que el manejo de errores
La mayor parte de estos problemas se evita ordenando las operaciones antes de escribir un solo
catch.
La regla del orden
- Todo lo reversible primero. Validaciones, reservas temporales, cálculos.
- Lo irreversible lo más tarde posible. Cobrar, enviar un correo, disparar algo a un tercero.
- Un único punto de no retorno. Que exista un paso claro después del cual el flujo se considera hecho, y que todo lo anterior se pueda abandonar sin consecuencias.
- Lo que no se puede deshacer, que quede pendiente. En vez de enviar el correo en el medio, encolarlo para después de la confirmación.
Reintentar sin duplicar
Si un flujo puede fallar, va a haber reintentos: del usuario, de la red o automáticos. La única forma de que el reintento no duplique efectos es que cada operación sea idempotente.
Antes de seguir, predecí
Y ahí aparece un caso que confunde: si la respuesta se pierde en el camino, el cliente no sabe si la operación ocurrió. Por eso la consulta de estado es tan importante como la operación: permite preguntar en vez de reintentar a ciegas.
Cuando hay que deshacer
Cuando algo irreversible ya pasó y el flujo falla, no queda deshacer sino compensar: una operación nueva que revierte el efecto —liberar la reserva, devolver el cupón, emitir una nota de crédito—.
Tres condiciones para que la compensación sirva
- Que exista y esté escrita, no improvisada el día del incidente.
- Que sea idempotente también, porque va a correr en un contexto ya inestable.
- Que deje rastro, para que soporte pueda explicar qué pasó cuando el usuario llame.
Más a fondo · nivel seniorEsto es una saga, aunque nadie la llame así
El patrón formal se llama saga: una secuencia de pasos locales, cada uno con su compensación, que reemplaza a la transacción distribuida. Lo importante no es el nombre sino la consecuencia de diseño: si el flujo cruza más de un servicio, la atomicidad no existe y hay que elegir entre consistencia eventual con compensaciones o rediseñar para que lo crítico ocurra en un solo lugar. La segunda opción se considera menos de lo que debería.
El flujo que falla en el tercer paso
El flujo: validar, reservar stock, cobrar, confirmar. Todavía no pasó nada en el mundo.
Cómo se diseña un flujo que puede fallar
Cierre
Autoevaluación
¿Lo entendiste?
Práctica