Fundamentos de MQTT

Session Expiry Interval e Clean Start no MQTT 5 Explicados

O MQTT 5 dividiu a antiga flag clean session em Clean Start e Session Expiry Interval. Veja como os dois se combinam, quais valores escolher e como verificá-los em um broker real.

Ilustração do session expiry interval MQTT com um cronômetro em contagem regressiva na sessão do broker depois que um cliente IoT se desconecta
Rode isso no seu próprio broker MQTTTenha um broker MQTT privado e gerenciado no plano Free e comece com exemplos de código prontos.
Teste grátis Exemplos de código Sem cartão de crédito

O session expiry interval MQTT informa ao broker por quanto tempo manter a sessão de um cliente depois que ele se desconecta e, junto com a flag Clean Start, substitui a flag clean session do MQTT 3.1.1, que era do tipo tudo ou nada. Neste artigo você vai aprender como as duas configurações se combinam, como o intervalo pode ser alterado no momento da desconexão e como escolher valores sensatos para sensores, gateways e serviços de backend.

Por Que o MQTT 5 Substituiu a Flag Clean Session

No MQTT 3.1.1, o cleanSession fazia dois trabalhos com um único bit. Defini-lo como false significava "retome minha sessão antiga e mantenha esta para sempre". Não havia como dizer "retome minha sessão, mas esqueça-a se eu sumir por mais de uma hora". Os brokers contornavam isso com configurações de expiração no servidor, o que fazia o comportamento variar entre brokers e deixava sessões abandonadas se acumulando.

O MQTT 5 separa as duas preocupações:

  • Clean Start (uma flag do CONNECT) responde: o broker deve descartar agora qualquer sessão existente?
  • Session Expiry Interval (uma property do CONNECT, em segundos) responde: por quanto tempo a sessão deve viver depois que a conexão de rede fecha?

O design está descrito na especificação MQTT 5.0 da OASIS e é uma das melhorias mais práticas abordadas na nossa visão geral dos recursos do MQTT 5.

Como Clean Start e Session Expiry se Combinam

Clean Start Session Expiry Interval Comportamento Equivalente no 3.1.1
true 0 (ou ausente) Sessão nova, excluída na desconexão cleanSession = true
false 0 (ou ausente) Retoma a sessão existente, se houver, excluída na desconexão Sem equivalente direto
true > 0 Descarta a sessão antiga e inicia uma nova que sobrevive à desconexão por N segundos Sem equivalente direto
false > 0 Retoma se existir, sobrevive à desconexão por N segundos cleanSession = false (com timeout)
false 0xFFFFFFFF Retoma se existir, nunca expira cleanSession = false

Alguns detalhes importam na prática:

  • O timer começa quando a conexão de rede fecha, não quando o cliente publicou pela última vez.
  • Se o cliente reconectar antes de o timer acabar, a sessão é retomada e o timer é cancelado.
  • Quando o intervalo termina, o broker exclui as assinaturas e todas as mensagens enfileiradas.
  • Se a sessão expirar, a mensagem de will é enviada no máximo nesse momento, mesmo que o will delay interval seja maior.

Alterando o Intervalo na Desconexão

O MQTT 5 permite que um cliente atualize a expiração no pacote DISCONNECT. Um dispositivo que entra em manutenção programada pode dizer "guarde minha sessão por um dia" ao sair, enquanto normalmente opera com um valor menor. Há uma restrição: se o cliente se conectou com expiração 0, não pode definir um valor diferente de zero na desconexão; o broker trata isso como erro de protocolo.

O Broker Pode Sobrescrever o Seu Valor

Um broker pode se recusar a manter sessões pelo tempo que você pede. Nesse caso ele retorna uma property Session Expiry Interval no CONNACK, e esse é o valor que vale. Sempre registre as properties do CONNACK durante o desenvolvimento para saber o número real. No broker de testes gratuito em broker.connectmq.com, o session expiry é limitado a 30 minutos.

Escolhendo um Session Expiry Interval MQTT

Pense em duas perguntas: por quanto tempo este cliente pode, realisticamente, ficar offline, e quão desatualizada uma mensagem enfileirada pode ficar antes de se tornar inútil?

Tipo de cliente Expiração sugerida Justificativa
Dashboard ao vivo, aba do navegador 0 Só os dados atuais importam; as retained messages preenchem a tela na conexão
Sensor ligado à tomada que só publica 0 a 300 s Pouco estado de sessão; uma expiração curta faz a limpeza rapidamente
Dispositivo que recebe comandos 1 a 24 h Os comandos devem sobreviver a quedas de Wi-Fi e interrupções curtas
Dispositivo a bateria que acorda a cada hora Um pouco mais que o intervalo de despertar A sessão precisa durar mais que o período de sono
Worker de backend que processa alarmes Horas, de acordo com o seu tempo de recuperação Alarmes perdidos precisam ser processados depois de redeploys
Cliente desativado ou de teste 0 Evita deixar sessões órfãs para trás

Combine intervalos de expiração longos com a property Message Expiry Interval do MQTT 5 em publicações sensíveis ao tempo. Um comando "ligar bomba" que fica seis horas em uma fila pode ser mais perigoso do que um que nunca é entregue.

Um Exemplo Prático: Sensor Sonolento com Comandos

Imagine um sensor a bateria em uma fazenda de soja que acorda a cada 15 minutos, publica uma leitura, verifica comandos de configuração e volta a dormir. Se a expiração da sessão fosse 0, qualquer comando enviado enquanto ele dormia seria descartado, porque não haveria sessão para enfileirá-lo. Se a expiração fosse infinita, um sensor que morresse em campo deixaria uma sessão acumulando comandos que ninguém vai ler. Um valor de cerca de 20 a 30 minutos cobre um despertar perdido mais alguma variação da rede, e a sessão desaparece sozinha quando o dispositivo realmente some. Envie os comandos com QoS 1 e um message expiry de algumas horas, e o dispositivo recebe tudo o que ainda for relevante na próxima conexão.

Configurando o Session Expiry no Código

Todos os exemplos usam um prefixo de demonstração único no servidor MQTT público (gratuito), que serve apenas para testes. Substitua s4e8 pela sua própria string aleatória; a área pública é visível para todos.

mosquitto_sub

# Retoma (ou cria) uma sessão que sobrevive 10 minutos após a desconexão
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 define Clean Start como false, e -x 600 define o Session Expiry Interval. A flag -d imprime o CONNACK, para você ver se o broker concedeu o 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());
});

Erros Comuns e Como Identificá-los

  1. Clean Start false, expiração 0. Desenvolvedores portam código 3.1.1, definem clean: false e esquecem a property de expiração. No MQTT 5, essa sessão é excluída no momento em que a conexão cai, então nada é enfileirado. Se as mensagens enfileiradas nunca aparecem, verifique isso primeiro.
  2. Expiração infinita em clientes de teste. Cada script descartável com ID único e 0xFFFFFFFF deixa uma sessão para trás. Use 0 em experimentos, a menos que esteja testando sessões.
  3. Ignorar o Session Present. Se o broker reiniciou ou a sessão expirou, o Session Present é 0 e suas assinaturas sumiram. Sempre assine novamente nesse caso.
  4. Presumir durabilidade após reinícios do broker. O session expiry descreve por quanto tempo uma sessão pode viver, não é uma garantia de armazenamento. A ConnectMQ mantém o estado das sessões em memória: ele sobrevive a desconexões do cliente pelo intervalo concedido, mas é apagado se o próprio broker reiniciar.
  5. Trocar client IDs. A expiração está vinculada ao client ID. Um novo ID é uma nova sessão; veja boas práticas de client ID MQTT.

Como Isso se Encaixa no Panorama Geral

O session expiry é a forma do MQTT 5 de usar sessões persistentes com segurança: você tem enfileiramento offline onde precisa e limpeza automática onde não precisa. Se ainda está aprendendo as peças do protocolo, o tutorial completo de MQTT é uma boa leitura complementar.

Use Sessões MQTT 5 na ConnectMQ

A ConnectMQ é um broker MQTT gerenciado com suporte completo ao MQTT 5.0, incluindo session expiry, message expiry, topic aliases e reason codes. Você pode testar combinações de Clean Start e expiração com o cliente MQTT no navegador do portal ou com o seu próprio código e depois levar as mesmas configurações para produção. Comece no plano Serverless gratuito, sem cartão de crédito, e conecte-se com os seus YOUR_USERNAME, YOUR_PASSWORD e YOUR_CLIENT_ID gerados.

Perguntas frequentes

Qual é o session expiry interval MQTT padrão?

Se a property estiver ausente, o session expiry interval é 0, o que significa que a sessão termina quando a conexão de rede fecha. Você precisa defini-lo explicitamente para ter uma sessão persistente no MQTT 5.

Qual é a diferença entre Clean Start e clean session?

O clean session do MQTT 3.1.1 controlava tanto o descarte da sessão antiga quanto a manutenção da nova. O Clean Start do MQTT 5 controla apenas o descarte no momento da conexão, enquanto o Session Expiry Interval controla por quanto tempo a sessão vive depois.

Qual é o session expiry interval máximo?

O máximo do protocolo é 4.294.967.295 segundos (0xFFFFFFFF), o que significa que a sessão nunca expira. Os brokers podem impor limites menores e informá-los no CONNACK; o servidor MQTT público da ConnectMQ permite até 30 minutos.

Posso alterar o session expiry ao desconectar?

Sim, enviando uma property Session Expiry Interval no DISCONNECT, a menos que você tenha se conectado originalmente com expiração 0.

Artigos relacionados

Por que Seu Cliente MQTT Fica Desconectando (e Como Corrigir)

Loops de reconexão estão entre os problemas mais comuns do MQTT. Conheça as cinco causas habituais, de client IDs duplicados a timeouts de keep alive e pacotes grandes demais, e siga um fluxo de diagnóstico que identifica a sua.

9 min de leitura

Quem Inventou o MQTT? A História dos Oleodutos à IoT

O MQTT foi inventado em 1999 por Andy Stanford-Clark, da IBM, e Arlen Nipper, da Arcom, para monitorar oleodutos via satélite. Acompanhe sua trajetória até o open source, a OASIS, a ISO e os brokers MQTT gerenciados na nuvem de hoje.

8 min de leitura

Todos os artigos →

Seu broker MQTT privado está a poucos cliques de distância

Crie uma conta, receba as credenciais do seu broker e conecte seu primeiro dispositivo — sem servidores para instalar, atualizar ou escalar.