Fundamentos de MQTT

Mensajes offline en MQTT: cómo encolan los brokers mensajes para clientes desconectados

Los brokers MQTT pueden retener mensajes para clientes temporalmente offline, pero solo en condiciones concretas. Conoce las reglas, los límites y una prueba reproducible que puedes hacer en cinco minutos.

Ilustración de mensajes offline en MQTT con la cola de un broker que retiene mensajes QoS 1 para un dispositivo IoT desconectado hasta que se reconecta
Pruébalo en tu propio broker MQTTConsigue un broker MQTT privado y gestionado con el plan Free y empieza con ejemplos de código listos para usar.
Pruébalo gratis Ejemplos de código Sin tarjeta

Los mensajes offline en MQTT son las publicaciones que un broker retiene para un suscriptor temporalmente desconectado y que entrega en cuanto vuelve. Este artículo explica con exactitud qué mensajes cumplen los requisitos, qué límites se aplican en los brokers reales y te guía por una prueba reproducible para que veas tú mismo cómo se encolan y se entregan.

Las cuatro condiciones de los mensajes offline en MQTT

El encolado no es automático. Un broker encola un mensaje para un cliente offline solo cuando se cumplen todas estas condiciones:

Condición Qué comprobar
El cliente tiene una sesión persistente MQTT 3.1.1: cleanSession = false. MQTT 5: Clean Start = false y Session Expiry Interval > 0
La sesión no ha caducado La caducidad de MQTT 5 aún no ha vencido y no se han superado los límites del broker
El cliente ya estaba suscrito a un filtro de topic coincidente La suscripción debe existir antes de que se quedara offline
El QoS efectivo es 1 o 2 El QoS de entrega es el menor entre el QoS de publicación y el de suscripción

Si falla cualquiera de las condiciones, el mensaje sencillamente no se entrega a ese cliente. El publicador no recibe ningún error, porque MQTT desacopla por diseño a publicadores y suscriptores. Por eso son tan habituales los fallos del tipo "mi dispositivo se perdió un comando": el publicador ve un PUBACK correcto del broker, pero el broker no tenía ningún motivo para conservar el mensaje para ese suscriptor concreto.

¿Y QoS 0?

QoS 0 es "como máximo una vez". La especificación permite que un broker encole mensajes QoS 0 para sesiones offline, pero no lo exige, y la mayoría de los brokers no lo hacen. Trata QoS 0 como algo solo en directo. Las diferencias entre niveles se explican en detalle en los niveles de QoS de MQTT explicados.

¿Y los mensajes retenidos?

Los mensajes retenidos son un mecanismo aparte. El broker guarda el último mensaje retenido de cada topic y lo envía a cualquiera que se suscriba, tenga o no sesión. Resuelven "¿cuál es el valor actual?", no "¿qué me he perdido?". Un cliente que se reconecta con una sesión limpia sigue recibiendo el último valor retenido al suscribirse, pero ninguna de las actualizaciones intermedias. Un buen diseño suele usar ambos: mensajes retenidos para el estado y mensajes QoS 1 encolados para eventos y comandos.

Límites que se aplican a las colas offline

Todos los brokers ponen límites a las colas, porque de lo contrario un cliente desconectado que nunca vuelve consumiría memoria para siempre.

  • Duración de la sesión. En MQTT 5, el session expiry interval decide cuánto sobrevive la cola. Cuando caduca, los mensajes encolados se descartan. En el servidor MQTT público gratuito broker.connectmq.com, pensado para pruebas y no para datos de producción, la caducidad de sesión está limitada a 30 minutos. Cómo elegir los valores se explica en el session expiry interval de MQTT.
  • Profundidad de la cola. Los brokers limitan el número de mensajes o bytes encolados por sesión. Al alcanzar el límite, los mensajes nuevos se descartan o los antiguos se expulsan, según el broker.
  • Caducidad del mensaje. Un publicador MQTT 5 puede fijar un Message Expiry Interval. Si un mensaje permanece en una cola más tiempo que ese, el broker lo descarta en lugar de entregar datos obsoletos.
  • Tamaño del mensaje. Los límites de tamaño de mensaje del plan y del broker también se aplican a los mensajes encolados (64 KB en el broker público, 256 KB en el plan Serverless Free de ConnectMQ y 1 MB en el plan Serverless de pago).
  • Reinicios del broker. Dónde residen las colas depende del broker. ConnectMQ guarda las sesiones y sus colas en memoria: sobreviven a las desconexiones de los clientes durante la duración de sesión concedida, pero no se conservan tras un reinicio del broker. Los clientes deben detectar una sesión perdida (Session Present = 0 en el CONNACK), volver a suscribirse y apoyarse en mensajes retenidos o en una resincronización a nivel de aplicación para recuperar el estado.

Prueba reproducible: observa la entrega offline

Esta prueba lleva unos cinco minutos con las herramientas de línea de comandos de mosquitto. Sustituye q5t9 por tu propia cadena aleatoria y mantén payloads inofensivos: cualquiera puede leer el área pública.

  1. Crea la sesión. Conecta un suscriptor con un ID fijo, Clean Start a false, una caducidad de sesión de 15 minutos y QoS 1:
mosquitto_sub -h broker.connectmq.com -p 1883 -V mqttv5 \
  -i offline-sub-q5t9 -c -x 900 -q 1 -v \
  -t 'connectmq/demo/q5t9/cmd/#'
  1. Desconéctate. Pulsa Ctrl+C.

  2. Publica una mezcla de niveles de QoS mientras el suscriptor está ausente:

H="-h broker.connectmq.com -p 1883 -V mqttv5 -i offline-pub-q5t9"
mosquitto_pub $H -q 0 -t 'connectmq/demo/q5t9/cmd/a' -m 'qos0 message'
mosquitto_pub $H -q 1 -t 'connectmq/demo/q5t9/cmd/b' -m 'qos1 message'
mosquitto_pub $H -q 1 -t 'connectmq/demo/q5t9/cmd/c' -m 'short-lived' \
  -D publish message-expiry-interval 5
mosquitto_pub $H -q 1 -t 'connectmq/demo/q5t9/other' -m 'not subscribed'
  1. Espera al menos 10 segundos y vuelve a ejecutar el comando del paso 1.

Deberías ver solo connectmq/demo/q5t9/cmd/b qos1 message. Este es el motivo por el que faltan los demás:

  • cmd/a era QoS 0, así que no se encoló.
  • cmd/c tenía una caducidad de mensaje de 5 segundos y se descartó en la cola.
  • other no coincidía con el filtro de suscripción.
  1. Repite sin -c en el paso 1. No se entrega nada al reconectar, porque la sesión se descartó al cerrarse la conexión.

El mismo patrón en Python

Un dispositivo que se reconecta y procesa todo lo que se perdió:

import paho.mqtt.client as mqtt
from paho.mqtt.properties import Properties
from paho.mqtt.packettypes import PacketTypes

TOPIC = "connectmq/demo/q5t9/cmd/#"

def on_connect(client, userdata, flags, reason_code, properties):
    if reason_code.is_failure:
        print("Connect failed:", reason_code)
        return
    print("Connected. Session present:", flags.session_present)
    if not flags.session_present:
        # Sesión nueva o perdida: suscríbete y recupera el estado por otra vía
        client.subscribe(TOPIC, qos=1)

def on_message(client, userdata, msg):
    print(f"Processing {msg.topic}: {msg.payload.decode()}")

client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2,
                     client_id="offline-py-q5t9",
                     protocol=mqtt.MQTTv5)
client.on_connect = on_connect
client.on_message = on_message
client.reconnect_delay_set(min_delay=1, max_delay=60)

props = Properties(PacketTypes.CONNECT)
props.SessionExpiryInterval = 900

client.connect("broker.connectmq.com", 1883, keepalive=60,
               clean_start=False, properties=props)
client.loop_forever()

Cómo diseñar pensando en los clientes offline

El encolado ayuda con las interrupciones cortas, pero no debería ser tu única herramienta de fiabilidad. Un diseño robusto combina varios mecanismos:

  1. Usa QoS 1 para comandos y eventos, y QoS 0 para telemetría de alta frecuencia en la que cada lectura sustituye a la anterior.
  2. Mantén una caducidad de sesión realista. Lo bastante larga para cubrir los cortes típicos y lo bastante corta para que los dispositivos muertos no acumulen colas.
  3. Fija la caducidad de mensaje en los comandos sensibles al tiempo, para que un dispositivo que vuelve al cabo de una hora no ejecute una instrucción obsoleta.
  4. Publica el estado como mensajes retenidos, para que cualquier cliente pueda resincronizarse al instante sin depender de una cola.
  5. Haz que los handlers sean idempotentes. QoS 1 puede entregar duplicados tras las reconexiones; incluye un ID de mensaje o un número de secuencia en el payload.
  6. Trata Session Present = 0 como un evento normal, no como un error.
  7. Espera una ráfaga al reconectar. Los clientes que han estado offline pueden recibir muchos mensajes de golpe; el Receive Maximum de MQTT 5 limita cuántos mensajes sin confirmar llegan en paralelo.

Para entender las sesiones en sí, lee las sesiones persistentes MQTT y el flag clean session. Si acabas de empezar, el tutorial de MQTT cubre primero los fundamentos de publicación/suscripción.

Resolución de problemas con mensajes offline que faltan

  • No llega nada tras reconectar: confirma que el client ID es idéntico, que Clean Start es false y, en MQTT 5, que la caducidad de sesión no es cero.
  • Llegan unos mensajes y otros no: compara el QoS de cada publicación con el de la suscripción y comprueba la caducidad de los mensajes.
  • Los mensajes llegan dos veces: es lo esperado con QoS 1 tras una confirmación interrumpida; elimina duplicados en la aplicación.
  • Session Present vale 0 inesperadamente: la sesión caducó, el client ID cambió o el broker se reinició.

Encola mensajes offline con ConnectMQ

ConnectMQ es un broker MQTT gestionado que admite sesiones persistentes, caducidad de sesión y caducidad de mensajes en MQTT 5.0, además de clientes MQTT 3.1.1. El plan Serverless Free admite QoS hasta 1, que es todo lo que requiere el encolado offline, y QoS 2 está disponible en los planes de pago. Crea tu broker gratuito sin tarjeta de crédito, conéctate con YOUR_USERNAME, YOUR_PASSWORD y YOUR_CLIENT_ID, y ejecuta la prueba anterior contra tu propio endpoint privado. Si estás comparando proveedores, descubre qué buscar en un broker MQTT en la nube.

Preguntas frecuentes

¿Almacena MQTT los mensajes cuando el suscriptor está offline?

Solo si el suscriptor tiene una sesión persistente, ya estaba suscrito a un topic coincidente y el QoS efectivo es 1 o 2. En caso contrario, el mensaje no se conserva para ese cliente.

¿Por qué se pierden mis mensajes QoS 0 mientras el dispositivo está offline?

Los mensajes QoS 0 normalmente no se encolan para sesiones offline; la especificación lo deja como opcional. Publica y suscríbete con QoS 1 si el mensaje debe sobrevivir a una desconexión.

¿Cuánto tiempo conserva un broker los mensajes offline?

Hasta que caduca la sesión, se alcanza un límite de cola, vence la caducidad del propio mensaje o, si las sesiones se guardan en memoria, el broker se reinicia. En ConnectMQ las sesiones residen en memoria, y el servidor MQTT público gratuito limita la caducidad de sesión a 30 minutos.

¿Sustituyen los mensajes retenidos al encolado offline?

No. Un mensaje retenido proporciona a un nuevo suscriptor el último valor de un topic, mientras que el encolado offline entrega cada mensaje QoS 1 o 2 que el cliente se perdió. La mayoría de los sistemas usan ambos.

Artículos relacionados

¿Quién inventó MQTT? La historia, de los oleoductos al IoT

MQTT lo inventaron en 1999 Andy Stanford-Clark, de IBM, y Arlen Nipper, de Arcom, para monitorizar oleoductos vía satélite. Sigue su camino hacia el open source, OASIS, ISO y los brokers MQTT gestionados en la nube de hoy.

8 min de lectura

Por qué tu cliente MQTT se desconecta constantemente (y cómo solucionarlo)

Los bucles de reconexión son uno de los problemas más habituales de MQTT. Conoce las cinco causas típicas, desde los client ID duplicados hasta los timeouts de keep alive y los paquetes demasiado grandes, y sigue un flujo de diagnóstico que localiza la tuya.

9 min de lectura

Todos los artículos →

Tu broker MQTT privado, a unos pocos clics

Crea una cuenta, obtén las credenciales de tu broker y conecta tu primer dispositivo, sin servidores que instalar, parchear ni escalar.