Fundamentos de MQTT

Will Delay Interval en MQTT: cómo evitar falsas alertas de desconexión

Un dispositivo que pierde el Wi-Fi durante tres segundos no debería despertar al ingeniero de guardia. El will delay interval de MQTT 5 retiene el mensaje Last Will lo suficiente para permitir una reconexión rápida.

Ilustración del will delay interval de MQTT con un temporizador que retiene un mensaje Last Will offline mientras un dispositivo IoT se reconecta rápidamente
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 will delay interval de MQTT es una propiedad de MQTT 5 que indica al broker que espere un número de segundos antes de publicar el mensaje Last Will de un cliente, y que lo cancele por completo si el cliente se reconecta a tiempo. En este artículo verás cómo suprime las alertas offline ruidosas causadas por breves cortes de red, cómo interactúa con la caducidad de sesión y cómo configurarlo en mosquitto, Python y Node.js.

El problema: alertas offline intermitentes

El Last Will and Testament es el mecanismo integrado de MQTT para anunciar que un cliente ha desaparecido. El cliente registra un mensaje de will al conectarse, normalmente un offline retenido en un topic de estado, y el broker lo publica si la conexión termina sin un DISCONNECT limpio.

En MQTT 3.1.1, el will se publica en cuanto el broker detecta el fallo. En redes reales, eso genera mucho ruido:

  • Un punto de acceso Wi-Fi traspasa un dispositivo a otro AP y la conexión TCP se reinicia.
  • Un módem móvil renegocia y el dispositivo vuelve en cuestión de segundos.
  • Un gateway reinicia su proceso MQTT tras un cambio de configuración.

Cada caso produce un mensaje offline seguido, momentos después, de online. Los dashboards parpadean, las reglas de alerta se disparan y los operadores aprenden a ignorar las alertas, lo que es peor que no tener ninguna.

Cómo funciona el will delay interval de MQTT

MQTT 5 añade el Will Delay Interval, una propiedad de cuatro bytes en segundos asociada al mensaje de will en el CONNECT. Cuando la conexión de red se cierra de forma anómala:

  1. El broker inicia un temporizador con el will delay interval.
  2. Si el mismo cliente se reconecta a la misma sesión antes de que venza el temporizador, el will no se publica.
  3. Si el temporizador vence antes, el will se publica como de costumbre.
  4. Si la sesión termina antes (porque vence el session expiry interval), el will se publica en ese momento.

El valor por defecto es 0, que reproduce el comportamiento de 3.1.1 de publicación inmediata.

La regla que todo el mundo pasa por alto: la caducidad de sesión

El will se publica cuando transcurre el retraso o cuando termina la sesión, lo que ocurra primero. Si el cliente se conecta con un session expiry interval de 0, la sesión termina en el instante en que se cierra la conexión, así que el will sale de inmediato y tu retraso no tiene efecto.

Will delay Session expiry Qué obtienes
0 cualquiera Will inmediato en una desconexión anómala
30 s 0 Will inmediato (la sesión terminó antes)
30 s 60 s Will a los 30 s salvo que el cliente se reconecte
30 s 10 s Will a los 10 s (la sesión terminó antes)
300 s 3600 s Will a los 5 minutos salvo que el cliente se reconecte

Así que, para usar el will delay, fija siempre un session expiry interval al menos tan largo como el retraso, y reconéctate con Clean Start a false para que el broker trate la nueva conexión como la misma sesión. Los detalles están en clean start y session expiry interval en MQTT 5.

El keep alive se suma al total

El temporizador solo arranca cuando el broker se da cuenta de que la conexión ha desaparecido. Si un dispositivo se queda sin alimentación, la detección tarda hasta 1,5 veces el keep alive. Con un keep alive de 60 segundos y un will delay de 30 segundos, el peor caso hasta el mensaje offline es de unos dos minutos. Presupuesta ambos juntos; consulta cómo elegir el intervalo keep alive de MQTT.

Cómo elegir un valor de will delay

Elige el retraso más corto que cubra tu tiempo normal de reconexión.

  • Dispositivos Wi-Fi con lógica de reconexión rápida: de 10 a 30 segundos.
  • Dispositivos móviles: de 30 a 120 segundos; el nuevo registro del módem es más lento.
  • Gateways que reinician servicios durante las actualizaciones: algo más que un reinicio típico.
  • Equipos relevantes para la seguridad: mantenlo corto, o en 0. Una alarma retrasada puede costar más que una falsa.

Una prueba práctica: registra durante una semana de funcionamiento real el tiempo entre desconexión y reconexión y elige un valor justo por encima de la mayoría de esos intervalos.

Cómo configurar el will delay en código

Todos los ejemplos usan el servidor MQTT público gratuito en broker.connectmq.com. Sustituye w3d8 por tu propia cadena aleatoria y recuerda que cualquiera puede leer el área pública, así que úsala solo para pruebas y nunca para datos de producción.

mosquitto_sub como dispositivo simulado

mosquitto_sub -h broker.connectmq.com -p 1883 -V mqttv5 \
  -i willdelay-dev-w3d8 -c -x 120 \
  --will-topic 'connectmq/demo/w3d8/status' \
  --will-payload 'offline' --will-qos 1 --will-retain \
  -D will will-delay-interval 30 \
  -t 'connectmq/demo/w3d8/cmd'

En otro terminal, observa el topic de estado:

mosquitto_sub -h broker.connectmq.com -p 1883 -i willdelay-watch-w3d8 \
  -v -t 'connectmq/demo/w3d8/status'

Pulsar Ctrl+C en mosquitto_sub envía un DISCONNECT limpio, que nunca dispara un will. Para simular un fallo real, mata el proceso (por ejemplo, con kill -9 sobre su ID de proceso, o desconectando la red). Después prueba dos casos: vuelve a lanzar el comando del dispositivo antes de 30 segundos y no aparecerá ningún offline; espera más y sí aparecerá.

Python (paho-mqtt 2.x)

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

STATUS = "connectmq/demo/w3d8/status"

client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2,
                     client_id="willdelay-py-w3d8",
                     protocol=mqtt.MQTTv5)

will_props = Properties(PacketTypes.WILLMESSAGE)
will_props.WillDelayInterval = 30          # segundos
client.will_set(STATUS, payload="offline", qos=1, retain=True,
                properties=will_props)

def on_connect(client, userdata, flags, reason_code, properties):
    print("Connected:", reason_code)
    # Anuncia que estamos online (sobrescribe un "offline" retenido)
    client.publish(STATUS, "online", qos=1, retain=True)

client.on_connect = on_connect

connect_props = Properties(PacketTypes.CONNECT)
connect_props.SessionExpiryInterval = 120  # debe ser >= will delay

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

Node.js (MQTT.js v5)

const mqtt = require("mqtt");
const STATUS = "connectmq/demo/w3d8/status";

const client = mqtt.connect("mqtts://broker.connectmq.com:8883", {
  clientId: "willdelay-node-w3d8",
  protocolVersion: 5,
  clean: false,
  keepalive: 30,
  properties: { sessionExpiryInterval: 120 },
  will: {
    topic: STATUS,
    payload: Buffer.from("offline"),
    qos: 1,
    retain: true,
    properties: { willDelayInterval: 30 },
  },
});

client.on("connect", () => {
  client.publish(STATUS, "online", { qos: 1, retain: true });
});

Un patrón online/offline completo

El will delay funciona mejor como parte de un diseño de presencia coherente:

  1. Registra un will offline retenido con un will delay y una caducidad de sesión acorde.
  2. Publica un online retenido inmediatamente después de cada conexión correcta.
  3. Antes de un apagado planificado, publica tú mismo un offline retenido y luego desconéctate limpiamente.
  4. Haz que los dashboards y las reglas de alerta lean únicamente el topic de estado retenido.
  5. Opcionalmente, añade una marca de tiempo o un motivo en un payload JSON para que los operadores vean por qué un dispositivo pasó a offline.

Encontrarás más patrones de presencia en el estado online de dispositivos MQTT. En un broker de ConnectMQ también puedes contrastarlo con el topic $SYS/broker/connection/{clientId}/state, que refleja la visión del broker sobre la conexión en bruto y no tu estado a nivel de aplicación.

Will delay frente a debouncing en la aplicación

Antes de MQTT 5, los equipos resolvían las intermitencias con debouncing en el consumidor: un dashboard o un servicio de alertas esperaba N segundos tras un mensaje offline y solo lanzaba una alarma si no llegaba un online a continuación. Eso sigue funcionando, pero cada consumidor tiene que implementar la misma lógica, y cada uno puede elegir una ventana distinta. El will delay traslada la decisión al broker, de modo que todos los suscriptores ven el mismo flujo de estado ya filtrado. La contrapartida es que el retraso se fija por cliente al conectarse, así que cambiarlo implica actualizar la configuración de los dispositivos en lugar de un único servicio backend.

Resolución de problemas del will delay

  • El will sigue disparándose de inmediato: la caducidad de sesión es 0 o más corta que el will delay, o te estás conectando con MQTT 3.1.1.
  • El will se dispara aunque el dispositivo se reconectó rápido: el dispositivo se reconectó con Clean Start a true o con otro client ID, así que era una sesión nueva.
  • El will nunca se dispara: el cliente se desconectó limpiamente o el retraso es más largo de lo que esperaste. Recuerda sumar el tiempo de detección del keep alive.
  • Se muestra un offline obsoleto tras reconectar: publica un online retenido en cada conexión, no solo en la primera.

¿Estos conceptos son nuevos para ti? El tutorial de MQTT explica wills, sesiones y mensajes retenidos desde el principio.

Construye un estado de dispositivos fiable en ConnectMQ

ConnectMQ es un broker MQTT gestionado con soporte completo de MQTT 5.0, incluidas las propiedades de will, la caducidad de sesión y los mensajes retenidos. Su portal añade reglas de alerta por umbral y un registro de alertas, así que unos datos de estado más limpios a nivel de protocolo se traducen en menos alertas ruidosas en las reglas que construyas sobre ellos. Empieza gratis con el plan Serverless, sin tarjeta de crédito, conéctate con YOUR_USERNAME, YOUR_PASSWORD y YOUR_CLIENT_ID, y prueba tu configuración de will delay en tu propio broker.

Preguntas frecuentes

¿Cuál es el will delay interval por defecto en MQTT?

El valor por defecto es 0 segundos, lo que significa que el mensaje de will se publica en cuanto el broker detecta una desconexión anómala, igual que en MQTT 3.1.1.

¿Por qué mi mensaje de will ignora el retraso?

Lo más habitual es que el session expiry interval sea 0 o más corto que el will delay. El broker publica el will cuando termina la sesión, así que la sesión debe durar al menos tanto como el retraso.

¿Está disponible el will delay en MQTT 3.1.1?

No. Es una funcionalidad de MQTT 5. Con MQTT 3.1.1 tendrías que aplicar debouncing a los eventos offline en la aplicación consumidora.

¿Una desconexión limpia dispara el mensaje de will?

No. Un DISCONNECT normal descarta el will. En MQTT 5, un cliente puede solicitar deliberadamente el will desconectándose con el reason code 0x04 (Disconnect with Will Message).

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.