Exactly-Once Semantics
Qué es
Exactly-once semantics describe un contrato donde cada unidad lógica válida produce un resultado una vez en el alcance declarado, bajo condiciones de identidad, persistencia y progreso. El término no tiene una interpretación operacional única: siempre hay que indicar qué ocurre una vez, para qué identidad y dentro de qué frontera.
| Expresión | Qué debe comprobarse | Qué no implica automáticamente |
|---|---|---|
| Exactly-once delivery | La frontera de entrega expone una vez cada mensaje lógico cubierto. | Un solo efecto de negocio o una sola publicación de la intención. |
| Exactly-once processing | El contrato de la plataforma define qué resultado o avance de procesamiento confirma una vez. | Que el código del handler se invoque físicamente una sola vez. |
| Exactly-once effects | El efecto de negocio relevante se confirma una vez por intención dentro del alcance. | Que todos los efectos externos o auxiliares estén incluidos. |
Algunos sistemas usan «processing» para resultados confirmados y permiten reejecutar cómputo tentativo. Otros contratos pueden restringir ejecuciones: hay que leer su definición, no imponer una universal. «Effectively once» también aparece para resultados equivalentes a una ejecución; es terminología que debe precisarse, no una garantía adicional por el nombre.
Qué problema resuelve
at-least-once permite repetición y at-most-once admite pérdida. Cuando ambas consecuencias son inaceptables para un efecto, hay que combinar una protección que impida confirmarlo dos veces con una recuperación que permita completarlo.
«Nunca dos veces» es una condición de seguridad. «Finalmente una vez» necesita progreso: una unidad válida, persistencia suficiente y componentes que se recuperen. Una promesa que impide duplicados pero puede abandonar trabajo sin recuperación sigue siendo, sobre ese efecto, solo at-most-once.
Cómo funciona
Identidad estable
Todos los intentos que corresponden a una intención deben poder reconocerse como tales. Si cada reintento genera otra identidad, la plataforma puede confirmar cada mensaje una vez y aun así duplicar una compra.
También debe decidir qué ocurre con una identidad reutilizada con otro contenido, con replays tardíos y con el vencimiento de su memoria. Una garantía temporal no se extiende más allá de esa ventana sin otro mecanismo.
Coordinación del resultado
Una implementación puede unir memoria de procesamiento, efecto y avance mediante una transacción dentro de un almacenamiento. Si el commit falla, ninguno queda confirmado; si ocurre, el reintento encuentra el resultado ya confirmado. El trabajo previo al commit puede repetirse.
Otra opción usa operaciones idempotentes en el sistema que recibe el efecto. Repetir una llamada puede preservar el mismo efecto, pero sigue siendo necesario demostrar que la intención termina y que la protección incluye todos los efectos relevantes.
Una memoria de deduplicación independiente del destino no cierra por sí sola la ventana entre ambos. Esa es una instancia del Dual-Write Problem.
Fronteras de plataforma y end-to-end
Una garantía acotada puede ser real y útil. No es equivalente a una garantía sobre toda la aplicación. Google Pub/Sub documenta condiciones de exactly-once delivery para suscriptores en una región y advierte que publicaciones distintas pueden crear copias de una misma intención con IDs diferentes. Pub/Sub: exactly-once delivery.
Dataflow, por su parte, documenta que una transformación puede ejecutarse más de una vez mientras sus resultados se confirman según su contrato; las llamadas a servicios externos no heredan automáticamente esa protección. Dataflow: exactly-once y side effects.
Una garantía end-to-end debe cubrir la intención del productor y el efecto final que observa el negocio. Un sistema intermedio que suprima repeticiones no reconoce necesariamente que el productor creó dos mensajes para la misma intención. El argumento end-to-end identifica por qué esa validación puede seguir siendo necesaria en la aplicación. Saltzer, Reed y Clark.
Ejemplo
Un consumidor registra un crédito en un libro contable local. La transacción confirma juntos el asiento y la identidad (libro, credito-17); la unicidad y el aislamiento impiden dos confirmaciones para esa identidad. El ack se envía después.
| Punto del fallo | Estado confirmado | Recuperación |
|---|---|---|
| Antes del commit | Sin asiento ni identidad confirmados | Reintentar la transacción. |
| Después del commit, antes del ack | Asiento e identidad confirmados | Reconocer el resultado previo y confirmar sin otro asiento. |
| Ack aceptado | Intención resuelta | Continuar con otras unidades. |
El contrato del ejemplo puede ofrecer un asiento por intención si la fuente mantiene el trabajo hasta su resolución, el almacenamiento conserva identidad y efecto, y el sistema vuelve a progresar. No demuestra una sola ejecución del handler ni funciona frente a cualquier pérdida permanente del almacenamiento.
Si el handler envía además un correo por un servicio externo, ese correo queda fuera de la prueba. Hace falta una garantía propia en ese servicio o un mecanismo adicional; «exactly-once processing» del consumidor no la aporta.
Cuándo usarlo
Es útil cuando duplicar o perder un efecto tiene una consecuencia importante y se puede definir una frontera verificable: asientos, transiciones de estado o resultados derivados con identidad estable.
Exigir el contrato para un efecto específico suele ser más útil que exigir «exactly once en todo». Permite revisar persistencia, identidad, concurrencia y recuperación con escenarios concretos.
Cuándo NO usarlo
No usar la etiqueta sin alcance ni trasladarla de un broker a una API externa. Tampoco afirmar que exactamente una vez es imposible en cualquier sistema: hay garantías alcanzables bajo fronteras y supuestos concretos.
En el caso opuesto, no prometer éxito eventual ante fallos permanentes ilimitados. Después de un timeout, dos estados son compatibles con lo observado: el destino no aplicó el efecto, o lo aplicó y perdió la respuesta. Sin consulta fiable, identidad compartida o coordinación, reenviar arriesga repetir y abandonar arriesga perder.
Trade-offs y alternativas
Identidades durables, transacciones, retención y recuperación cuestan recursos y coordinación; pueden aumentar latencia y restringir destinos. Una transacción entre sistemas puede limitar disponibilidad frente a fallos.
Alternativas explícitas incluyen at-least-once con efectos idempotentes, aceptación de duplicados seguida de reconciliación, o at-most-once con pérdidas toleradas. Compensar después de un duplicado no significa que el duplicado nunca haya existido.
Errores comunes: confundir una sola confirmación con una sola ejecución, omitir un efecto externo, ignorar expiración de claves y asumir que una transacción local incluye el ack del transporte.
Relaciones
- delivery-guarantees aporta unidad, frontera y supuestos.
- at-least-once y at-most-once separan las condiciones de progreso y no repetición.
- deduplication reconoce trabajo previo; idempotency limita el efecto de repetir.
- dual-write-problem identifica los estados que una garantía local no puede confirmar conjuntamente.