Fundamentos

MQTT Last Will and Testament (LWT) explicado

Como funciona o Last Will and Testament do MQTT: quando o broker o envia, o will delay do MQTT 5 e o padrão de presença online/offline retido, com exemplos.

Atualizado · 6 min de leitura

Dispositivos em redes instáveis raramente têm a chance de se despedir. Baterias acabam, o Wi-Fi cai, processos travam. O Last Will and Testament (LWT) do MQTT permite que um cliente registre antecipadamente uma mensagem que o broker publica em seu nome caso o cliente desapareça de forma inesperada. É o bloco de construção padrão para detecção de presença e alertas em sistemas MQTT.

Como o Last Will funciona

O will é declarado no pacote CONNECT. Ele tem as mesmas partes de uma publicação normal:

CampoSignificado
Will TopicOnde o broker vai publicar, por exemplo acme/sensor-17/status
Will PayloadO corpo da mensagem, por exemplo offline
Will QoS0, 1 ou 2 — veja níveis de QoS
Will RetainSe o will é armazenado como mensagem retida
Will Properties (MQTT 5)Will Delay Interval, Message Expiry, Content Type, User Properties…

O broker guarda o will junto com a sessão e não faz nada com ele enquanto o cliente está conectado. O que acontece depois depende de como a conexão termina.

Quando o will é publicado?

O broker publica o will quando a conexão de rede é encerrada sem uma desconexão normal, inclusive quando:

  • o broker detecta um erro de I/O ou uma falha de rede;
  • o cliente não se comunica dentro do período de keep-alive — o broker espera até 1,5 × o intervalo de keep-alive antes de considerar a conexão morta;
  • o cliente fecha a conexão TCP/WebSocket sem enviar DISCONNECT;
  • o broker fecha a conexão por causa de um erro de protocolo.

O will não é publicado quando o cliente envia um DISCONNECT normal; um encerramento limpo o apaga. O MQTT 5 adiciona uma exceção: um cliente pode se desconectar com o reason code 0x04 (Disconnect with Will Message) para encerrar de forma limpa e ainda assim ter o will enviado.

Will Delay Interval (MQTT 5)

No MQTT 3.1.1, o will dispara imediatamente. Isso gera ruído para dispositivos que se reconectam rápido após uma breve oscilação de rede: os assinantes veem offline e, um segundo depois, online. O MQTT 5 adiciona a propriedade Will Delay Interval (em segundos):

  • O broker espera o atraso antes de publicar o will.
  • Se o cliente se reconectar com o mesmo client ID dentro desse atraso, o will não é enviado.
  • O will é publicado quando o atraso expira ou quando a sessão termina, o que acontecer primeiro — então um will delay maior que o Session Expiry Interval fica, na prática, limitado por ele.
Will do MQTT 5 com atraso de 30 segundos (MQTT.js)
const client = mqtt.connect('wss://broker.emqx.io:8084/mqtt', {
  protocolVersion: 5,
  clientId: 'sensor-17',
  properties: { sessionExpiryInterval: 300 },
  will: {
    topic: 'acme/sensor-17/status',
    payload: 'offline',
    qos: 1,
    retain: true,
    properties: { willDelayInterval: 30 },
  },
});

O padrão de presença: status online/offline

O uso mais comum do LWT é combiná-lo com mensagens retidas (retained) para que qualquer cliente saiba, a qualquer momento, se um dispositivo está online:

  1. Conecte com um will: tópico acme/sensor-17/status, payload offline, QoS 1, retain = true.
  2. Logo após o CONNACK, publique online no mesmo tópico, QoS 1, retain = true. Isso sobrescreve qualquer offline antigo que tenha ficado da última vez.
  3. No encerramento normal, publique você mesmo offline (retido) e depois envie DISCONNECT. Como o will é descartado em uma desconexão limpa, é essa publicação explícita que mantém o status correto.
  4. Em caso de falha, o broker publica o will offline retido por você.

Os dashboards então assinam acme/+/status e recebem imediatamente o status atual de cada dispositivo, graças à retenção.

presence.mjs (MQTT.js)
import mqtt from 'mqtt';

const statusTopic = 'acme/sensor-17/status';

const client = mqtt.connect('wss://broker.hivemq.com:8884/mqtt', {
  clientId: 'sensor-17',
  keepalive: 30,
  will: { topic: statusTopic, payload: 'offline', qos: 1, retain: true },
});

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

process.on('SIGINT', () => {
  client.publish(statusTopic, 'offline', { qos: 1, retain: true }, () => client.end());
});

Armadilhas comuns

  • Colisões de client ID. Se um segundo cliente se conecta com o mesmo client ID, o broker desconecta o primeiro — e publica o will dele. Duas instâncias disputando um mesmo ID produzem um status que fica alternando entre online e offline.
  • Bibliotecas que sempre se desconectam de forma limpa. Alguns SDKs enviam DISCONNECT ao encerrar o processo, e o will nunca dispara. Teste matando o processo ou cortando a rede.
  • Esquecer o retain. Um will não retido só é visto pelos clientes inscritos naquele momento.
  • Autorização. O will é publicado com as permissões do cliente. Se o cliente não tiver permissão para publicar no tópico do will, o broker pode rejeitar a conexão ou descartar o will silenciosamente. Veja erros de conexão MQTT.

Definindo um will pela linha de comando

Os clientes do Mosquitto aceitam opções de will diretamente, o que facilita experimentos rápidos. Inicie um assinante em um terminal, depois conecte um segundo cliente com um will e mate-o com Ctrl+C ou fechando o terminal:

bash
# terminal 1 — watch the status topic
mosquitto_sub -h test.mosquitto.org -t 'testmqtt/lwt-demo/#' -v

# terminal 2 — connect with a retained will and a 10 s keep-alive
mosquitto_sub -h test.mosquitto.org -t 'testmqtt/lwt-demo/cmd' -k 10 \
  --will-topic 'testmqtt/lwt-demo/status' --will-payload 'offline' \
  --will-qos 1 --will-retain

Dependendo de como o processo termina, o cliente pode ou não conseguir enviar o DISCONNECT. A forma mais confiável de ver o will é cortar a rede (por exemplo, desativando o Wi-Fi) e esperar o keep-alive expirar — exatamente o tipo de falha para o qual o LWT foi criado.

Como testar o Last Will

  1. Em uma aba do cliente MQTT online, assine testmqtt/lwt-demo/#.
  2. Em uma segunda aba, conecte com um will em testmqtt/lwt-demo/status e um keep-alive curto.
  3. Feche a segunda aba sem desconectar. Dentro da janela de keep-alive, a primeira aba recebe o will.

Teste no cliente MQTT online

Perguntas frequentes

Por que o meu Last Will do MQTT não está sendo enviado?

O broker só publica o will quando um cliente se desconecta de forma abrupta. Se a sua biblioteca cliente envia um pacote DISCONNECT ao fechar, o will é descartado. Verifique também o keep-alive: o broker pode esperar até 1,5 vez o intervalo de keep-alive antes de perceber uma conexão morta.

Posso alterar o Last Will depois de conectar?

Não. O will faz parte do pacote CONNECT e não pode ser modificado durante a sessão. Para alterá-lo, desconecte e conecte de novo com um novo will.

A mensagem de Last Will deve ser retida?

Para tópicos de presença e status, sim. Um will offline retido faz com que clientes que assinam depois ainda vejam o dispositivo como offline, em vez de não verem nada ou verem uma mensagem online antiga.