Reintentar sin duplicar: por qué la idempotencia importa
Los reintentos son una herramienta básica para aumentar la confiabilidad de una automatización. Una API puede responder con un error temporal, una conexión puede interrumpirse o una ejecución puede quedar inconclusa. En esos casos, volver a intentar suele ser razonable. El problema aparece cuando el sistema no puede distinguir entre la operación no ocurrió y la operación ocurrió pero no recibí la confirmación.
Ahí entra la idempotencia. Una operación idempotente puede repetirse sin producir efectos adicionales después de la primera ejecución válida. No significa que todos los intentos sean ignorados, sino que el sistema reconoce que varios intentos pertenecen a la misma operación lógica.
Considere una integración que debe registrar una transacción en otro sistema. El primer intento envía la solicitud, pero la respuesta se pierde por un problema de red. Desde el punto de vista del cliente, el resultado es incierto: la operación pudo haber sido procesada o pudo haber fallado antes de llegar al servidor. Si el cliente vuelve a enviar una solicitud nueva sin una identidad estable, existe el riesgo de crear un segundo registro.
La solución consiste en asignar un identificador único a la operación, normalmente llamado operation_id o idempotency_key. Ese valor debe permanecer igual en todos los reintentos de la misma operación. Cada intento individual puede tener su propio identificador para fines de observabilidad, pero todos deben apuntar a la misma identidad lógica.
La protección debe estar cerca de la fuente de verdad. Una restricción UNIQUE en la base de datos, por ejemplo, impide que dos solicitudes con la misma idempotency_key creen dos registros diferentes. Si la operación ya existe, el sistema puede devolver la confirmación almacenada anteriormente en lugar de ejecutar nuevamente el efecto.
Esto es más confiable que intentar detectar duplicados comparando atributos parecidos. Dos operaciones distintas pueden tener el mismo monto, la misma descripción o datos muy similares. La similitud es útil para análisis, pero no constituye una identidad inequívoca.
Cuando una operación requiere varias escrituras relacionadas, la transacción también importa. Si se crea un registro pero falla la actualización del estado que indica que el proceso terminó, el siguiente retry podría interpretar que la operación sigue pendiente. Agrupar cambios críticos en una transacción reduce esos estados intermedios inconsistentes.
Los reintentos también deben combinarse con estados explícitos. El sistema necesita saber si una operación está pendiente, en proceso, confirmada o fallida. Esa información permite decidir si corresponde reintentar, devolver un resultado existente o escalar el caso.
La idea central es simple: retry responde cuándo vuelvo a intentarlo y la idempotencia responde cómo evito repetir el efecto. Un sistema confiable necesita ambas respuestas.
Diseñar reintentos sin idempotencia puede convertir una falla temporal en un problema de datos. Diseñar idempotencia sin estados ni transacciones puede dejar huecos difíciles de recuperar. La combinación de identidad estable, restricción determinística, estados claros y transacciones cuando corresponden permite recuperar fallos sin perder consistencia.
Comentarios
Publicar un comentario