INTRODUCTION
Un botón Reintentar promete que otro intento ayudará al usuario a terminar la misma acción. Esa promesa falla cuando la interfaz interpreta la ausencia de respuesta como prueba de que no ocurrió nada.
La pregunta útil llega antes del indicador de carga: si el primer intento funcionó pero su respuesta se perdió, ¿qué hará el siguiente clic? Los equipos de producto e ingeniería necesitan una respuesta compartida.
Dar una identidad duradera a la acción
Imaginemos una aplicación de trabajo colaborativo. Un cliente pulsa Crear espacio, el servidor lo crea y la conexión se interrumpe antes de recibir la confirmación. Un segundo clic con una nueva identidad de solicitud podría crear otro espacio. Desactivar el botón brevemente ayuda con los clics rápidos; no resuelve una recarga, otra pestaña o una respuesta tardía.
Un registro de operación puede conservar la intención inicial del usuario a través de esas interrupciones. La interfaz retoma ese registro en lugar de empezar de nuevo. Soporte puede consultar la misma operación sin pedir al cliente que reconstruya lo sucedido.
La Builders’ Library de AWS explica cómo los identificadores aportados por quien llama a la API permiten distinguir un reintento de una petición realmente nueva. Unos parámetros idénticos no expresan esa diferencia: alguien puede querer dos recursos iguales.
Revisar las garantías de la clave
Una clave de idempotencia identifica una operación repetida, pero sus garantías dependen de cada API. La referencia de Stripe indica que las solicitudes repetidas con la misma clave devuelven el resultado guardado, incluidos los errores del servidor. Las claves pueden eliminarse después de al menos 24 horas; reutilizar una clave eliminada genera una nueva solicitud.
La retención pasa así a formar parte del diseño de producto. Una intervención de soporte días después no puede asumir que el proveedor todavía recuerda el primer intento. Conservar la relación entre la operación local y el recurso del proveedor permite comprobar un resultado incierto antes de emitir otra orden. Una intención distinta merece su propia operación, no una modificación silenciosa de la anterior.
Un evento entregado todavía necesita un trabajo terminado
El camino de vuelta tiene sus propios fallos. Stripe documenta entregas duplicadas de webhooks y ninguna garantía sobre su orden. Un reenvío manual exitoso no cancela automáticamente los reintentos programados.
En nuestro ejemplo, recibir una notificación y terminar la creación del espacio deberían ser estados separados. Una bandeja de entrada persistente puede registrar la recepción; un worker puede seguir el trabajo resultante. Una restricción en la base de datos o una asignación transaccional evita que dos workers se consideren los primeros a la vez. Si el procesamiento falla, el registro debe seguir siendo recuperable y no quedar marcado definitivamente como completado.
Los efectos externos necesitan su propia protección. Una transacción de base de datos no puede incluir de forma atómica un servicio de correo independiente. Registrar la acción pendiente, usar las garantías de deduplicación del proveedor cuando existan y hacer visibles los resultados ambiguos permite preparar su reconciliación. Una cola por sí sola no garantiza que todo el proceso se ejecute exactamente una vez.
Mostrar la incertidumbre sin abandonar al usuario
Tres estados de interfaz resultan más útiles que un error genérico:
- En proceso: mantener visible la operación y explicar cómo se actualizará su estado.
- Resultado sin confirmar: comprobar la operación existente; evitar presentar una nueva solicitud como inofensiva.
- Fallo confirmado: ofrecer un reintento cuando el sistema sabe que es seguro, o explicar el siguiente paso de recuperación.
Para una acción reversible y de poco impacto, puede bastar una implementación más sencilla. La objeción es válida: una orquestación persistente tiene un coste de mantenimiento. La opción proporcionada depende del daño que pueda causar un duplicado y de la facilidad para deshacerlo. Crear un segundo borrador y enviar una segunda invitación no tienen las mismas consecuencias.
Poner a prueba la promesa antes del lanzamiento
- Perder la respuesta después de confirmar la escritura en el servidor.
- Enviar la misma operación desde dos pestañas a la vez.
- Entregar dos veces el mismo evento e invertir el orden de dos eventos.
- Interrumpir el worker entre registrar la recepción y terminar el trabajo.
- Reabrir una operación antigua e incierta después del plazo de retención del proveedor.
En cada prueba, comprobar el resultado visible para el usuario y el registro de recuperación, además del estado HTTP. El objetivo es un sistema que pueda explicar lo ocurrido y terminar de forma segura lo que el usuario quiso hacer.
Para ampliar el enfoque, consulta qué flujos de desarrollo conviene automatizar primero (artículo en inglés). Una revisión de producto puede empezar por una sola acción costosa y mapear sus estados inciertos antes de añadir más automatización.
Portada: ilustración conceptual original generada con IA, con el logotipo oficial de Blanche añadido por separado.
