Delivery Guarantees
Qué es
Una garantía de entrega es un contrato sobre cuántas veces una unidad lógica llega a una frontera determinada y bajo qué condiciones. La unidad puede ser un mensaje, una solicitud o un registro; la frontera puede ser un broker, una suscripción o una aplicación. Sin precisar ambas, decir «se entrega una vez» no permite evaluar un diseño.
Para un mensaje lógico m, sea D(m) el número de entregas en la frontera elegida durante el período considerado:
| Contrato | Restricción sobre D(m) | Consecuencia |
|---|---|---|
| at-most-once | 0 o 1 | Puede perderse; no debe entregarse repetido en ese alcance. |
| at-least-once | 1 o más, bajo los supuestos de progreso | Evita la pérdida dentro del modelo asumido, pero admite duplicados. |
| exactly-once-semantics | 1, si se refiere literalmente a entrega | Hay que comprobar qué identifica el mensaje y qué frontera protege. |
Estas restricciones no describen automáticamente cuántas veces se ejecuta código ni cuántos efectos se confirman. Una entrega aceptada por el broker, una ejecución del consumidor y una actualización de negocio son hechos distintos.
Qué problema resuelve
El emisor y el receptor no observan simultáneamente el mismo estado. Después de enviar, el emisor puede recibir una confirmación, una negativa o ninguna respuesta. Un timeout deja incertidumbre: puede haberse perdido la solicitud o solamente la confirmación.
El contrato permite elegir qué hacer ante esa incertidumbre: abandonar, volver a enviar o consultar un estado durable. La elección debe responder al costo de perder una intención y al costo de repetir su efecto.
Cómo funciona
Primero se define qué constituye una unidad lógica. Reenviar pedido-42 conserva la intención; crear un ID nuevo en cada intento puede convertirla, para el sistema, en varias unidades independientes.
Después se delimita la cadena:
productor → aceptación del broker → entrega al consumidor → efecto de negocioCada tramo tiene su propio contrato. La confirmación del productor no prueba que el consumidor haya completado un pago. Un acknowledgement o ack es una confirmación cuyo significado debe definirse: recibido en memoria, persistido o procesado son compromisos diferentes. La documentación de RabbitMQ distingue explícitamente las confirmaciones de publicación de los acknowledgements de consumo; esa separación ilustra por qué las garantías de dos tramos no deben confundirse. RabbitMQ: acknowledgements y confirms.
Un contrato útil debe especificar:
- Admisión: desde cuándo el sistema asume responsabilidad por la unidad.
- Identidad: cómo reconoce varios intentos del mismo mensaje.
- Persistencia: qué estado sobrevive a reinicios y qué fallos de almacenamiento se toleran.
- Progreso: qué conectividad, capacidad y disponibilidad se necesitan para completar la entrega.
- Tiempo: retención, expiración y período de reintentos.
- Resultado terminal: qué ocurre con mensajes inválidos, descartados o que nunca pueden procesarse.
La prohibición de duplicados es una propiedad de seguridad: algo incorrecto no ocurre. La entrega eventual es una propiedad de progreso: algo deseado acaba ocurriendo. Una partición permanente o un destinatario que nunca se recupera puede impedir el progreso; ningún nombre de garantía elimina ese supuesto.
Ejemplo
Un pedido debe generar una preparación de envío. El productor publica pedido-42; el consumidor registra la preparación y luego confirma. La confirmación se pierde y el mensaje vuelve a entregarse.
Hay dos entregas y dos intentos de procesamiento, pero puede existir una sola preparación si el consumidor aplica deduplicación coordinada con su escritura, o si la operación cumple idempotencia. Esa protección no cambia retrospectivamente el transporte a exactly-once delivery: limita el efecto observable.
Si el pedido y su publicación se escriben en sistemas distintos, aparece además el Dual-Write Problem. Una garantía de entrega del broker no cubre un evento que nunca llegó a publicarse.
Cuándo usarlo
Usar este análisis al definir contratos de APIs, eventos, jobs y consumidores. Es especialmente útil para revisar dónde se confirma progreso y quién puede reintentar tras un resultado incierto.
El contrato debería permitir explicar un caso de fallo concreto y cómo se recupera, no limitarse a seleccionar una etiqueta comercial.
Cuándo NO usarlo
No usar una garantía de entrega como sustituto de un requisito de negocio sobre efectos. Tampoco como promesa de orden, latencia máxima, atomicidad entre sistemas o ejecución exitosa: son propiedades independientes que necesitan sus propios supuestos.
Trade-offs y alternativas
Evitar reentregas simplifica algunos caminos de recuperación, pero puede aceptar pérdida. Reintentar mejora el progreso y exige tratar duplicados. Reducirlos mediante memoria durable y coordinación introduce costos de almacenamiento, retención, concurrencia y disponibilidad.
Consultar el resultado por ID y reconciliar estados puede complementar el contrato cuando no hay una confirmación concluyente. No recupera mágicamente efectos externos ni convierte dos escrituras independientes en una transacción.
Errores comunes: contar intentos en lugar de mensajes lógicos; asumir que persistente significa imposible de perder; y trasladar la garantía de un broker a toda la aplicación. El argumento end-to-end recuerda que ciertas propiedades deben verificarse en los extremos que realmente las necesitan. Saltzer, Reed y Clark: End-to-End Arguments in System Design.
Relaciones
- at-most-once y at-least-once desarrollan las políticas de entrega ante incertidumbre.
- exactly-once-semantics separa entrega, procesamiento, efectos y fronteras de garantía.
- idempotency y deduplication permiten manejar repeticiones con responsabilidades diferentes.
- dual-write-problem explica por qué coordinar el efecto con otra escritura requiere algo adicional.
- retry define cuándo y bajo qué límites repetir; una política de intentos no demuestra por sí sola una garantía de entrega.
- reliable-execution ofrece el recorrido editorial del cluster.