O will delay interval MQTT é uma property do MQTT 5 que instrui o broker a esperar alguns segundos antes de publicar a mensagem de Last Will de um cliente e a cancelá-la completamente se o cliente se reconectar a tempo. Neste artigo você vai ver como ela suprime alertas de offline ruidosos causados por breves oscilações de rede, como interage com o session expiry e como configurá-la no mosquitto, em Python e em Node.js.
O Problema: Alertas de Offline Intermitentes
O Last Will and Testament é a forma nativa do MQTT de anunciar que um cliente desapareceu. O cliente registra uma mensagem de will na conexão, normalmente um offline retido em um topic de status, e o broker a publica se a conexão terminar sem um DISCONNECT limpo.
No MQTT 3.1.1, o will é publicado assim que o broker detecta a falha. Em redes reais, isso gera ruído:
- Um ponto de acesso Wi-Fi transfere o dispositivo para outro AP e a conexão TCP é reiniciada.
- Um modem celular renegocia e o dispositivo volta em segundos.
- Um gateway reinicia o processo MQTT após uma mudança de configuração.
Cada caso produz uma mensagem offline seguida, instantes depois, de online. Os dashboards piscam, as regras de alerta disparam e os operadores aprendem a ignorar os alertas, o que é pior do que não ter nenhum.
Como Funciona o Will Delay Interval MQTT
O MQTT 5 adiciona o Will Delay Interval, uma property de quatro bytes, em segundos, anexada à mensagem de will no CONNECT. Quando a conexão de rede fecha de forma anormal:
- O broker inicia um timer com a duração do will delay interval.
- Se o mesmo cliente se reconectar à mesma sessão antes de o timer expirar, o will não é publicado.
- Se o timer expirar primeiro, o will é publicado normalmente.
- Se a sessão terminar primeiro (porque o session expiry interval acabou), o will é publicado nesse momento.
O padrão é 0, o que reproduz o comportamento do 3.1.1 de publicação imediata.
A Regra Que Todo Mundo Esquece: Session Expiry
O will é publicado quando o atraso passa ou quando a sessão termina, o que acontecer primeiro. Se o cliente se conecta com session expiry interval igual a 0, a sessão termina no instante em que a conexão fecha, então o will sai imediatamente e o seu atraso não tem efeito.
| Will delay | Session expiry | O que acontece |
|---|---|---|
| 0 | qualquer | Will imediato em desconexão anormal |
| 30 s | 0 | Will imediato (a sessão terminou primeiro) |
| 30 s | 60 s | Will após 30 s, a menos que o cliente se reconecte |
| 30 s | 10 s | Will após 10 s (a sessão terminou primeiro) |
| 300 s | 3600 s | Will após 5 minutos, a menos que o cliente se reconecte |
Portanto, para usar o will delay, sempre defina um session expiry interval pelo menos tão longo quanto o atraso e reconecte com Clean Start igual a false, para que o broker trate a nova conexão como a mesma sessão. Os detalhes estão em clean start e session expiry interval no MQTT 5.
O Keep Alive Soma ao Total
O timer só começa quando o broker percebe que a conexão caiu. Se um dispositivo perde energia, a detecção leva até 1,5 vez o keep alive. Com keep alive de 60 segundos e will delay de 30 segundos, o tempo no pior caso até uma mensagem offline é de cerca de dois minutos. Planeje os dois juntos; veja como escolher o intervalo de keep alive MQTT.
Escolhendo um Valor de Will Delay
Escolha o menor atraso que cubra o seu tempo normal de reconexão.
- Dispositivos Wi-Fi com lógica de reconexão rápida: 10 a 30 segundos.
- Dispositivos celulares: 30 a 120 segundos; o novo registro do modem é mais lento, algo comum em fazendas ou em mineradoras com cobertura 4G irregular.
- Gateways que reiniciam serviços durante atualizações: um pouco mais do que um reinício típico.
- Equipamentos relevantes para a segurança: mantenha curto, ou 0. Um alarme atrasado pode custar mais do que um falso.
Um teste prático: registre o tempo entre desconexão e reconexão durante uma semana de operação real e escolha um valor logo acima da maior parte desses intervalos.
Configurando o Will Delay no Código
Todos os exemplos usam o servidor MQTT público (gratuito) em broker.connectmq.com. Substitua w3d8 pela sua própria string aleatória e lembre-se de que a área pública pode ser lida por qualquer pessoa, então use-a só para testes, nunca para dados de produção.
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'
Em outro terminal, acompanhe o topic de status:
mosquitto_sub -h broker.connectmq.com -p 1883 -i willdelay-watch-w3d8 \
-v -t 'connectmq/demo/w3d8/status'
Um Ctrl+C no mosquitto_sub envia um DISCONNECT limpo, que nunca dispara um will. Para simular uma falha real, mate o processo (por exemplo, com kill -9 no ID do processo, ou desconectando a rede). Depois teste dois casos: reinicie o comando do dispositivo em menos de 30 segundos e nenhum offline aparece; espere mais e ele aparece.
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 (sobrescreve um "offline" retido)
client.publish(STATUS, "online", qos=1, retain=True)
client.on_connect = on_connect
connect_props = Properties(PacketTypes.CONNECT)
connect_props.SessionExpiryInterval = 120 # deve 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 });
});
Um Padrão Completo de Online/Offline
O will delay funciona melhor como parte de um design de presença consistente:
- Registre um will
offlineretido com will delay e session expiry compatível. - Publique um
onlineretido imediatamente após cada conexão bem-sucedida. - Antes de um desligamento planejado, publique você mesmo um
offlineretido e depois desconecte de forma limpa. - Deixe que dashboards e regras de alerta leiam apenas o topic de status retido.
- Opcionalmente, adicione um timestamp ou motivo em um payload JSON para que os operadores vejam por que um dispositivo ficou offline.
Mais padrões de presença são abordados em status online de dispositivos MQTT. Em um broker ConnectMQ você também pode fazer a verificação cruzada com o topic $SYS/broker/connection/{clientId}/state, que reflete a visão do broker sobre a conexão bruta, e não o seu status no nível da aplicação.
Will Delay Versus Debouncing na Aplicação
Antes do MQTT 5, as equipes resolviam a intermitência fazendo debouncing no consumidor: um dashboard ou serviço de alertas esperava N segundos após uma mensagem offline e só disparava um alarme se nenhum online viesse em seguida. Isso ainda funciona, mas cada consumidor precisa implementar a mesma lógica, e cada um pode escolher uma janela diferente. O will delay move a decisão para o broker, então todo assinante vê o mesmo fluxo de status já filtrado. A contrapartida é que o atraso é definido por cliente no momento da conexão, então alterá-lo significa atualizar a configuração dos dispositivos, e não de um único serviço de backend.
Solução de Problemas do Will Delay
- O will ainda dispara imediatamente: o session expiry é 0 ou menor que o will delay, ou você está se conectando com MQTT 3.1.1.
- O will dispara mesmo com o dispositivo reconectando rapidamente: o dispositivo se reconectou com Clean Start igual a true ou com outro client ID, então era uma nova sessão.
- O will nunca dispara: o cliente se desconectou de forma limpa ou o atraso é maior do que o tempo que você esperou. Lembre-se de somar o tempo de detecção do keep alive.
- Um
offlineobsoleto aparece após a reconexão: publique umonlineretido a cada conexão, não apenas na primeira.
É novo nesses conceitos? O tutorial de MQTT explica wills, sessões e retained messages desde o início.
Construa um Status de Dispositivos Confiável na ConnectMQ
A ConnectMQ é um broker MQTT gerenciado com suporte completo ao MQTT 5.0, incluindo properties de will, session expiry e retained messages. O portal oferece regras de alerta por limite e um log de alertas, então dados de status mais limpos no nível do protocolo significam menos alertas ruidosos nas regras que você criar sobre eles. Comece grátis no plano Serverless, sem cartão de crédito, conecte-se com YOUR_USERNAME, YOUR_PASSWORD e YOUR_CLIENT_ID e teste suas configurações de will delay no seu próprio broker.
Perguntas frequentes
Qual é o will delay interval MQTT padrão?
O padrão é 0 segundo, o que significa que a mensagem de will é publicada assim que o broker detecta uma desconexão anormal, exatamente como no MQTT 3.1.1.
Por que minha mensagem de will ignora o atraso?
Na maioria das vezes o session expiry interval é 0 ou menor que o will delay. O broker publica o will quando a sessão termina, então a sessão precisa durar pelo menos tanto quanto o atraso.
O will delay está disponível no MQTT 3.1.1?
Não. É um recurso do MQTT 5. Com MQTT 3.1.1 você precisaria fazer o debouncing dos eventos de offline na aplicação consumidora.
Uma desconexão limpa dispara a mensagem de will?
Não. Um DISCONNECT normal descarta o will. No MQTT 5, um cliente pode solicitar deliberadamente o will desconectando com o reason code 0x04 (Disconnect with Will Message).



