Fundamentos de MQTT

Session Expiry Interval y Clean Start en MQTT 5 explicados

MQTT 5 dividió el antiguo flag clean session en Clean Start y Session Expiry Interval. Así se combinan ambos, estos son los valores que conviene elegir y así se comprueban en un broker real.

Ilustración del session expiry interval de MQTT con una cuenta atrás sobre la sesión de un broker tras desconectarse un cliente IoT
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

El session expiry interval de MQTT indica al broker cuánto tiempo debe conservar la sesión de un cliente después de que este se desconecte y, junto con el flag Clean Start, sustituye al flag clean session de MQTT 3.1.1, que funcionaba a todo o nada. En este artículo aprenderás cómo se combinan ambos ajustes, cómo puede cambiarse el intervalo en el momento de la desconexión y cómo elegir valores sensatos para sensores, gateways y servicios backend.

Por qué MQTT 5 sustituyó el flag clean session

En MQTT 3.1.1, cleanSession hacía dos trabajos con un solo bit. Ponerlo a false significaba "reanuda mi sesión antigua y conserva esta para siempre". No había forma de decir "reanuda mi sesión, pero olvídala si desaparezco más de una hora". Los brokers lo resolvían con ajustes de caducidad en el servidor, lo que hacía que el comportamiento variara entre brokers y que se acumularan sesiones abandonadas.

MQTT 5 separa ambas cuestiones:

  • Clean Start (un flag del CONNECT) responde a: ¿debe el broker descartar ahora mismo cualquier sesión existente?
  • Session Expiry Interval (una propiedad del CONNECT, en segundos) responde a: ¿cuánto debe vivir la sesión después de cerrarse la conexión de red?

El diseño se describe en la especificación OASIS MQTT 5.0 y es una de las mejoras más prácticas que repasamos en nuestra visión general de las novedades de MQTT 5.

Cómo se combinan Clean Start y Session Expiry

Clean Start Session Expiry Interval Comportamiento Equivalente en 3.1.1
true 0 (o ausente) Sesión nueva, eliminada al desconectar cleanSession = true
false 0 (o ausente) Reanuda la sesión existente si la hay, eliminada al desconectar Sin equivalente directo
true > 0 Descarta la sesión antigua e inicia una nueva que sobrevive N segundos a la desconexión Sin equivalente directo
false > 0 Reanuda si existe y sobrevive N segundos a la desconexión cleanSession = false (con un timeout)
false 0xFFFFFFFF Reanuda si existe y nunca caduca cleanSession = false

En la práctica importan algunos detalles:

  • El temporizador arranca cuando se cierra la conexión de red, no cuando el cliente publicó por última vez.
  • Si el cliente se reconecta antes de que venza el temporizador, la sesión se reanuda y el temporizador se cancela.
  • Cuando transcurre el intervalo, el broker elimina las suscripciones y los mensajes encolados.
  • Si la sesión caduca, el mensaje de will se envía como muy tarde en ese momento, aunque el will delay interval sea más largo.

Cambiar el intervalo al desconectar

MQTT 5 permite a un cliente actualizar la caducidad en su paquete DISCONNECT. Un dispositivo que entra en un mantenimiento planificado puede decir "conserva mi sesión durante un día" al marcharse, aunque normalmente funcione con un valor más corto. Hay una restricción: si el cliente se conectó con una caducidad de 0, no puede fijar un valor distinto de cero al desconectar; el broker lo trata como un error de protocolo.

El broker puede imponerse

Un broker puede negarse a conservar las sesiones tanto tiempo como pides. En ese caso devuelve una propiedad Session Expiry Interval en el CONNACK, y ese es el valor vigente. Registra siempre las propiedades del CONNACK durante el desarrollo para conocer el número real. En el servidor MQTT público gratuito broker.connectmq.com, pensado para pruebas y prototipos, la caducidad de sesión está limitada a 30 minutos.

Cómo elegir el session expiry interval de MQTT

Piensa en dos preguntas: ¿cuánto tiempo puede estar realmente offline este cliente? y ¿qué antigüedad puede tener un mensaje encolado antes de que deje de ser útil?

Tipo de cliente Caducidad sugerida Motivo
Dashboard en directo, pestaña del navegador 0 Solo importan los datos actuales; los mensajes retenidos llenan la pantalla al conectar
Sensor conectado a la red eléctrica que solo publica De 0 a 300 s Poco estado de sesión; una caducidad corta limpia rápido
Dispositivo que recibe comandos De 1 a 24 h Los comandos deben sobrevivir a caídas de Wi-Fi y cortes breves
Dispositivo con batería que despierta cada hora Algo más que el intervalo de despertar La sesión debe durar más que el periodo de reposo
Worker backend que procesa alarmas Horas, ajustadas a tu tiempo de recuperación Las alarmas perdidas deben procesarse tras los redespliegues
Cliente dado de baja o de pruebas 0 Evita dejar sesiones huérfanas

Combina los intervalos de caducidad largos con la propiedad Message Expiry Interval de MQTT 5 en las publicaciones sensibles al tiempo. Un comando "arrancar bomba" que pasa seis horas en una cola puede ser más peligroso que uno que nunca se entrega.

Un ejemplo práctico: sensor dormilón con comandos

Imagina un sensor con batería que despierta cada 15 minutos, publica una lectura, comprueba si hay comandos de configuración y vuelve a dormir. Si su caducidad de sesión fuera 0, cualquier comando enviado mientras dormía se descartaría, porque no habría sesión en la que encolarlo. Si la caducidad fuera infinita, un sensor que muriera en campo dejaría una sesión que seguiría acumulando comandos que nadie leerá. Un valor de unos 20 a 30 minutos cubre un despertar perdido más algo de variabilidad de red, y la sesión desaparece por sí sola cuando el dispositivo ya no existe de verdad. Envía los comandos con QoS 1 y una caducidad de mensaje de unas pocas horas, y el dispositivo recibirá todo lo que siga siendo relevante la próxima vez que se conecte.

Cómo configurar la caducidad de sesión en código

Todos los ejemplos usan un prefijo de demostración único en el servidor MQTT público gratuito. Sustituye s4e8 por tu propia cadena aleatoria; el área pública es visible para todo el mundo.

mosquitto_sub

# Reanuda (o crea) una sesión que sobrevive 10 minutos tras la desconexión
mosquitto_sub -h broker.connectmq.com -p 1883 -V mqttv5 \
  -i expiry-demo-s4e8 -c -x 600 -q 1 -v -d \
  -t 'connectmq/demo/s4e8/commands/#'

-c pone Clean Start a false y -x 600 fija el Session Expiry Interval. El flag -d imprime el CONNACK, así que puedes ver si el broker concedió el valor.

Python (paho-mqtt 2.x)

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

def on_connect(client, userdata, flags, reason_code, properties):
    granted = getattr(properties, "SessionExpiryInterval", None)
    print("Connected:", reason_code,
          "| session present:", flags.session_present,
          "| broker override:", granted)
    if not flags.session_present:
        client.subscribe("connectmq/demo/s4e8/commands/#", qos=1)

def on_message(client, userdata, msg):
    print("Command:", msg.topic, msg.payload.decode())

client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2,
                     client_id="expiry-py-s4e8",
                     protocol=mqtt.MQTTv5)
client.on_connect = on_connect
client.on_message = on_message

connect_props = Properties(PacketTypes.CONNECT)
connect_props.SessionExpiryInterval = 600

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

try:
    input("Press Enter to disconnect with a 30 minute expiry...\n")
finally:
    bye = Properties(PacketTypes.DISCONNECT)
    bye.SessionExpiryInterval = 1800
    client.disconnect(properties=bye)
    client.loop_stop()

Node.js (MQTT.js v5)

const mqtt = require("mqtt");

const client = mqtt.connect("mqtts://broker.connectmq.com:8883", {
  clientId: "expiry-node-s4e8",
  protocolVersion: 5,
  clean: false, // Clean Start = false
  properties: { sessionExpiryInterval: 600 },
});

client.on("connect", (connack) => {
  console.log("session present:", connack.sessionPresent,
              "props:", connack.properties);
  if (!connack.sessionPresent) {
    client.subscribe("connectmq/demo/s4e8/commands/#", { qos: 1 });
  }
});

client.on("message", (topic, payload) => {
  console.log(topic, payload.toString());
});

Errores habituales y cómo detectarlos

  1. Clean Start a false y caducidad 0. Los desarrolladores portan código de 3.1.1, ponen clean: false y se olvidan de la propiedad de caducidad. En MQTT 5 esa sesión se elimina en cuanto cae la conexión, así que nunca se encola nada. Si los mensajes encolados no aparecen nunca, compruébalo primero.
  2. Caducidad infinita en clientes de prueba. Cada script desechable con un ID único y 0xFFFFFFFF deja una sesión tras de sí. Usa 0 en los experimentos, salvo que estés probando sesiones.
  3. Ignorar Session Present. Si el broker se reinició o la sesión caducó, Session Present vale 0 y tus suscripciones han desaparecido. Vuelve a suscribirte siempre en ese caso.
  4. Dar por hecha la durabilidad ante reinicios del broker. La caducidad de sesión describe cuánto tiempo puede vivir una sesión, no una garantía de almacenamiento. ConnectMQ guarda el estado de sesión en memoria: sobrevive a las desconexiones de los clientes durante el intervalo concedido, pero se borra si el propio broker se reinicia.
  5. Cambiar los client IDs. La caducidad está ligada al client ID. Un ID nuevo es una sesión nueva; consulta las buenas prácticas del client ID de MQTT.

Cómo encaja en el panorama general

La caducidad de sesión es la manera de MQTT 5 de usar sesiones persistentes con seguridad: obtienes encolado offline donde lo necesitas y limpieza automática donde no. Si todavía estás aprendiendo las piezas del protocolo, el tutorial completo de MQTT es una buena lectura complementaria.

Usa sesiones MQTT 5 en ConnectMQ

ConnectMQ es un broker MQTT gestionado con soporte completo de MQTT 5.0, incluidos la caducidad de sesión, la caducidad de mensajes, los alias de topic y los reason codes. Puedes probar combinaciones de Clean Start y caducidad con el cliente MQTT integrado en el navegador del portal o con tu propio código, y después llevar los mismos ajustes a producción. Empieza con el plan Serverless gratuito, sin tarjeta de crédito, y conéctate con tus YOUR_USERNAME, YOUR_PASSWORD y YOUR_CLIENT_ID generados.

Preguntas frecuentes

¿Cuál es el session expiry interval por defecto en MQTT?

Si la propiedad no está presente, el session expiry interval es 0, lo que significa que la sesión termina cuando se cierra la conexión de red. Debes fijarlo explícitamente para obtener una sesión persistente en MQTT 5.

¿Qué diferencia hay entre Clean Start y clean session?

Clean session, en MQTT 3.1.1, controlaba tanto el descarte de la sesión antigua como la conservación de la nueva. Clean Start, en MQTT 5, solo controla el descarte en el momento de conectar, mientras que el Session Expiry Interval controla cuánto vive la sesión después.

¿Cuál es el session expiry interval máximo?

El máximo del protocolo es 4.294.967.295 segundos (0xFFFFFFFF), lo que significa que la sesión nunca caduca. Los brokers pueden imponer límites más bajos e indicarlos en el CONNACK; el servidor MQTT público gratuito de ConnectMQ permite hasta 30 minutos.

¿Puedo cambiar la caducidad de sesión al desconectarme?

Sí, enviando la propiedad Session Expiry Interval en el DISCONNECT, salvo que te conectaras originalmente con una caducidad de 0.

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.