At-Least-Once Delivery
Qué es
At-least-once delivery permite entregar una unidad lógica una o más veces. Bajo sus supuestos de persistencia y progreso, una unidad aceptada no se abandona sin llegar a la frontera comprometida. No significa que cada entrega tenga éxito de negocio ni que la repetición sea infrecuente.
El productor puede tener esta garantía hacia el broker y el consumidor recibir una garantía distinta. Delivery Guarantees define cómo declarar unidad, frontera y condiciones antes de asignar la etiqueta.
Qué problema resuelve
Si la falta de respuesta provoca abandonar una operación, una solicitud perdida puede desaparecer definitivamente. Reintentar el envío o reentregar un mensaje pendiente permite recuperar progreso tras fallos temporales.
El costo es la ambigüedad: una confirmación perdida se observa igual que una ejecución que nunca ocurrió. Repetir protege contra pérdida, pero puede volver a ejecutar trabajo ya completado.
Cómo funciona
Un esquema típico conserva el mensaje como pendiente mientras no exista una confirmación aceptada. El consumidor procesa, hace durable el efecto que debe proteger y después envía un ack, una confirmación de procesamiento. Si pierde la conexión o vence el plazo sin confirmación, el sistema permite reentregar.
recibir m → confirmar efecto → enviar ack
↘ ack perdido → reentregar mLa ventana entre efecto y ack prefiere una repetición a perder trabajo. Confirmar antes de hacer durable el efecto introduce una ventana de pérdida: no garantiza at-least-once processing, aunque el mensaje se haya entregado al proceso. La guía de fiabilidad de RabbitMQ señala la necesidad de retransmitir publicaciones sin confirmación y que esa confirmación puede haberse perdido después de aceptar el mensaje. RabbitMQ: Reliability Guide.
La garantía necesita condiciones explícitas:
- El registro pendiente sobrevive a los fallos incluidos en el contrato.
- Existe capacidad para seguir intentando y el destinatario vuelve a estar disponible.
- El mensaje no expira ni se descarta antes de alcanzar la frontera prometida.
- Un reintento conserva la identidad necesaria para reconocer la intención.
Reintentar un mensaje inválido indefinidamente no asegura un efecto válido. Si se limita la cantidad de intentos y se envía a una cola de errores, esa cola es una salida operativa que necesita revisión o reparación; no equivale al éxito original. Si el mensaje ya llegó al consumidor, la entrega pudo cumplirse aunque el negocio no se completara.
Ejemplo
credito-17 solicita incrementar un saldo en 10. El consumidor actualiza la base de datos y cae antes del ack. La reentrega ejecuta nuevamente el incremento: el saldo sube 20 para una sola intención.
Hay dos formas de limitar ese efecto, según el dominio:
- Diseñar una operación idempotente, por ejemplo registrar un crédito con identidad única en lugar de aplicar un incremento sin identidad.
- Usar deduplicación durable y coordinar el registro de procesamiento con la actualización local.
Guardar credito-17 en memoria volátil después de actualizar no cierra la ventana del crash. Guardarlo de forma durable en otra escritura independiente puede introducir el Dual-Write Problem.
Cuándo usarlo
Es adecuado para trabajo cuyo costo de pérdida es alto y cuya repetición puede controlarse: actualizaciones derivadas, eventos y tareas recuperables. La aplicación debe saber qué hace con duplicados antes de habilitar reintentos automáticos.
También permite reconstruir un efecto pendiente tras una interrupción si la fuente conserva la intención y el contrato admite volver a presentarla.
Cuándo NO usarlo
No elegirlo sin protección para efectos irreversibles, como un pago externo sin identidad estable ni consulta de resultado. La entrega repetida no aporta esa protección.
Si una muestra antigua perdió utilidad y se reemplaza con la siguiente, aceptar pérdida puede ser más razonable que mantener un backlog ilimitado; ese caso puede favorecer at-most-once.
Trade-offs y alternativas
retry consume recursos y exige condiciones de seguridad y progreso. backoff y jitter permiten espaciar intentos y reducir su sincronización, pero no limitan por sí solos la concurrencia. Un límite operativo necesita recuperación posterior si se pretende conservar progreso eventual.
At-least-once no garantiza orden. Una actualización vieja puede reaparecer después de otra nueva; comparar versiones o secuencias resuelve un problema distinto de suprimir duplicados.
Errores comunes son asumir que un ack acredita efectos externos, cambiar el ID al reintentar, tratar la cola de errores como éxito y considerar que un duplicado raro no necesita diseño. exactly-once-semantics analiza cuándo se confirman efectos una sola vez sin prometer una sola ejecución física.
Relaciones
- delivery-guarantees establece el alcance de la promesa.
- idempotency y deduplication controlan consecuencias de reentregas con responsabilidades diferentes.
- at-most-once compara la alternativa que acepta pérdida para evitar repetición.
- dual-write-problem muestra el límite de actualizar sistemas independientes.
- exactly-once-semantics precisa qué se necesita para elevar la garantía sobre efectos.