¿Alguna vez RabbitMQ te ha dado alguno de estos errores?

[error] <0.XXX.0> Discarding message from queue 'queue_lazy_ha_ttl' on delivery because it has expired (message TTL exceeded)
[error] <0.XXX.0> Unexpected ACK/NACK on expired message in queue 'queue_lazy_ha_ttl'. Index and store out of sync.
[error] <0.XXX.0> Inconsistent state detected: ACK for message already expired and purged from queue 'queue_lazy_ha_ttl'
[error] <0.1234.0> CRASH REPORT Process <0.2345.0> exited with reason: {{badmatch,{error,einval}}, ...}

Vamos a ver porque son ocasionados y como remediarlo.

¿Qué es una «classic mirrored queue» en RabbitMQ?

Una cola clásica (classic queue) en RabbitMQ es el tipo de cola tradicional que se ha utilizado durante años.
Cuando hablamos de mirrored (HA) queue, nos referimos a una configuración donde la cola y todos sus mensajes son replicados en varios nodos del cluster RabbitMQ, para garantizar alta disponibilidad ante la caída de un nodo.

  • Master: Nodo principal que gestiona la cola.
  • Slaves: Nodos secundarios que mantienen una réplica idéntica de la cola.
  • Si el nodo master cae, uno de los slaves toma el control automáticamente.

La replicación se controla mediante políticas (policies), por ejemplo:

  • La cola puede quedar marcada como corrupta e inutilizable.
  • RabbitMQ puede reiniciar el proceso del nodo afectado (“Stopping node because of queue index corruption”).
  • Los consumidores pueden recibir mensajes ya expirados, o errores 404/NOT_FOUND.
  • Puede requerir borrar la cola a mano y recrearla (¡pérdida de mensajes!).

¿Qué es el modo Lazy en RabbitMQ?

El modo Lazy es una característica de RabbitMQ diseñada para colas que pueden llegar a almacenar muchos mensajes en espera antes de ser consumidos.
Su objetivo principal es minimizar el uso de memoria RAM en el servidor, moviendo los mensajes directamente a disco tan pronto como sea posible.

¿Cómo funciona una cola Lazy?

  • Por defecto, cuando publicas mensajes en una cola estándar («normal»), RabbitMQ los mantiene en memoria (RAM) hasta que hay demasiados, y solo entonces los va moviendo a disco si es necesario.
  • En una cola Lazy, RabbitMQ escribe los mensajes en disco desde el principio, incluso aunque haya suficiente memoria disponible.
    Solo mueve mensajes de disco a memoria cuando van a ser entregados a un consumidor.

¿Cuándo deberías usar una cola Lazy?

  • Cuando esperas altos picos de mensajes o retenciones largas (backlogs), y no puedes permitir que la RAM del servidor se llene.
  • Casos típicos:
    • Sistemas donde el ritmo de producción de mensajes es mucho mayor que el de consumo.
    • Procesamiento batch o colas de tareas retrasadas.
    • Integraciones donde los consumidores pueden quedar inactivos durante un tiempo.

¿Qué problemas reales puede provocar?

  • Pérdida de mensajes: Mensajes “resucitados” que nunca deberían ser entregados, o mensajes perdidos por corrupción.
  • Cola inutilizable: La cola se corrompe y no puede ser consumida ni publicada, hay que eliminarla manualmente.
  • Caída de nodos: Si la corrupción se propaga, nodos del cluster pueden reiniciarse para proteger la integridad global (mnesia).
  • Parón del sistema: Si usas políticas como pause_minority, parte del cluster puede quedar en modo solo lectura hasta que resuelvas el problema.

¿Cómo solucionar el problema cuando aparece?

Borra la cola corrupta:
Si la cola está inutilizable, elimínala desde la UI o por consola:

rabbitmqctl delete_queue <queue_lazy_ha_ttl>

Reinicia el nodo afectado:
A veces, tras borrar la cola, el nodo vuelve a la normalidad.

Comprueba el estado del cluster:

  • Verifica si hay particiones o nodos en estado “down”.
  • Revisa los logs para buscar más colas afectadas.

¿Cómo evitar este bug en producción?

  • No uses classic mirrored queues:
  • Están deprecadas. Usa Quorum Queues para alta disponibilidad real.
  • Si usas mirroring, evita modo lazy + TTL juntos:
  • Es esta combinación la que activa el bug.
  • No reinicies o desconectes nodos del cluster durante grandes purgas/expiraciones:
  • Haz mantenimientos programados en ventanas de bajo tráfico.
  • Monitorea siempre los logs del cluster RabbitMQ:
  • Busca errores de “corruption”, “expired”, “ACK”, “badmatch”, “einval”, etc.
  • Planifica la migración a Quorum Queues:
  • Son más robustas, no presentan este bug y soportan HA de verdad.

¿Cómo se soluciona a nivel de arquitectura?

Quorum Queues es la respuesta moderna de RabbitMQ al problema de las classic mirrored.

  • Replican el log de mensajes en todos los nodos usando un protocolo tipo Raft.
  • Soportan TTL, expiración, y alta disponibilidad de verdad.
  • Son el único tipo de cola recomendado para nuevos desarrollos.

Si aun no estas preparado para la migración una buena idea para evitar el problema es aumentando el TTL o aumentar los consumidores para evitar que los mensajes lleguen al punto de pasar a la TTL y los consuman al mismo tiempo.