Fundamentos de MQTT

Mensagens Offline MQTT: Como os Brokers Enfileiram Mensagens para Clientes Desconectados

Brokers MQTT podem guardar mensagens para clientes temporariamente offline, mas só em condições específicas. Conheça as regras, os limites e um teste reproduzível que você executa em cinco minutos.

Ilustração de mensagens offline MQTT mostrando a fila de um broker guardando mensagens QoS 1 para um dispositivo IoT desconectado até ele se reconectar
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

Mensagens offline MQTT são as publicações que um broker guarda para um assinante temporariamente desconectado e entrega quando ele volta, como um gateway de fazenda que perde o sinal celular por alguns minutos. Este artigo explica exatamente quais mensagens se qualificam, quais limites se aplicam em brokers reais e conduz você por um teste reproduzível para que você veja o enfileiramento e a entrega acontecendo.

As Quatro Condições para Mensagens Offline MQTT

O enfileiramento não é automático. Um broker só enfileira uma mensagem para um cliente offline quando todas estas condições são verdadeiras:

Condição O que verificar
O cliente tem uma sessão persistente MQTT 3.1.1: cleanSession = false. MQTT 5: Clean Start = false e Session Expiry Interval > 0
A sessão não expirou A expiração do MQTT 5 ainda não passou e os limites do broker não foram excedidos
O cliente já assinava um filtro de topic correspondente A assinatura precisa existir antes de ele ficar offline
O QoS efetivo é 1 ou 2 O QoS de entrega é o menor entre o QoS do publish e o da assinatura

Se qualquer condição falhar, a mensagem simplesmente não é entregue àquele cliente. Não há erro para o publicador, porque o MQTT desacopla publicadores de assinantes por design. É por isso que bugs do tipo "meu dispositivo perdeu um comando" são tão comuns: o publicador recebe um PUBACK de sucesso do broker, mas o broker não tinha motivo para guardar a mensagem para aquele assinante específico.

E o QoS 0?

QoS 0 é "no máximo uma vez". A especificação permite que um broker enfileire mensagens QoS 0 para sessões offline, mas não exige isso, e a maioria dos brokers não o faz. Trate o QoS 0 como exclusivamente ao vivo. As diferenças entre os níveis são abordadas em detalhes em níveis de QoS MQTT explicados.

E as Retained Messages?

As retained messages são um mecanismo separado. O broker guarda a última mensagem retida por topic e a envia a qualquer um que assine, tenha ou não uma sessão. Elas resolvem "qual é o valor atual?", não "o que eu perdi?". Um cliente que se reconecta com sessão limpa ainda recebe o último valor retido ao assinar, mas nenhuma das atualizações intermediárias. Um bom design costuma usar as duas coisas: retained messages para estado e mensagens QoS 1 enfileiradas para eventos e comandos.

Limites Que se Aplicam às Filas Offline

Todo broker impõe limites às filas, porque, caso contrário, um cliente desconectado que nunca volta consumiria memória para sempre.

  • Tempo de vida da sessão. No MQTT 5, o session expiry interval decide por quanto tempo a fila sobrevive. Quando ele expira, as mensagens enfileiradas são descartadas. No servidor MQTT público broker.connectmq.com, o session expiry é limitado a 30 minutos. A escolha dos valores é abordada em session expiry interval MQTT.
  • Profundidade da fila. Os brokers limitam o número de mensagens ou de bytes enfileirados por sessão. Quando o limite é atingido, novas mensagens são descartadas ou as antigas são removidas, dependendo do broker.
  • Expiração da mensagem. Um publicador MQTT 5 pode definir um Message Expiry Interval. Se uma mensagem ficar na fila por mais tempo do que isso, o broker a descarta em vez de entregar dados obsoletos.
  • Tamanho da mensagem. Os limites de tamanho de mensagem do plano e do broker também valem para mensagens enfileiradas (64 KB no servidor MQTT público, 256 KB no plano Serverless Free da ConnectMQ, 1 MB no plano Serverless pago).
  • Reinícios do broker. O local onde as filas ficam depende do broker. A ConnectMQ mantém as sessões e suas filas em memória: elas sobrevivem a desconexões do cliente pelo tempo de vida de sessão concedido, mas não são mantidas após um reinício do broker. Os clientes devem detectar uma sessão perdida (Session Present = 0 no CONNACK), assinar novamente e contar com retained messages ou com uma ressincronização na camada de aplicação para recuperar o estado.

Teste Reproduzível: Veja a Entrega Offline Acontecer

Este teste leva cerca de cinco minutos com as ferramentas de linha de comando do mosquitto. Substitua q5t9 pela sua própria string aleatória e mantenha os payloads inofensivos: o servidor MQTT público pode ser lido por qualquer pessoa e serve para testes e protótipos, não para dados de produção.

  1. Crie a sessão. Conecte um assinante com ID fixo, Clean Start false, session expiry de 15 minutos e QoS 1:
mosquitto_sub -h broker.connectmq.com -p 1883 -V mqttv5 \
  -i offline-sub-q5t9 -c -x 900 -q 1 -v \
  -t 'connectmq/demo/q5t9/cmd/#'
  1. Fique offline. Pressione Ctrl+C.

  2. Publique uma mistura de níveis de QoS enquanto o assinante está ausente:

H="-h broker.connectmq.com -p 1883 -V mqttv5 -i offline-pub-q5t9"
mosquitto_pub $H -q 0 -t 'connectmq/demo/q5t9/cmd/a' -m 'qos0 message'
mosquitto_pub $H -q 1 -t 'connectmq/demo/q5t9/cmd/b' -m 'qos1 message'
mosquitto_pub $H -q 1 -t 'connectmq/demo/q5t9/cmd/c' -m 'short-lived' \
  -D publish message-expiry-interval 5
mosquitto_pub $H -q 1 -t 'connectmq/demo/q5t9/other' -m 'not subscribed'
  1. Espere pelo menos 10 segundos e execute de novo o comando da etapa 1.

Você deve ver apenas connectmq/demo/q5t9/cmd/b qos1 message. Veja por que cada uma das outras não aparece:

  • cmd/a era QoS 0, então não foi enfileirada.
  • cmd/c tinha um message expiry de 5 segundos e foi descartada na fila.
  • other não correspondia ao filtro da assinatura.
  1. Repita sem -c na etapa 1. Nada é entregue na reconexão, porque a sessão foi descartada quando a conexão fechou.

O Mesmo Padrão em Python

Um dispositivo que se reconecta e processa tudo o que perdeu:

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

TOPIC = "connectmq/demo/q5t9/cmd/#"

def on_connect(client, userdata, flags, reason_code, properties):
    if reason_code.is_failure:
        print("Connect failed:", reason_code)
        return
    print("Connected. Session present:", flags.session_present)
    if not flags.session_present:
        # Sessão nova ou perdida: assine e recupere o estado de outra forma
        client.subscribe(TOPIC, qos=1)

def on_message(client, userdata, msg):
    print(f"Processing {msg.topic}: {msg.payload.decode()}")

client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2,
                     client_id="offline-py-q5t9",
                     protocol=mqtt.MQTTv5)
client.on_connect = on_connect
client.on_message = on_message
client.reconnect_delay_set(min_delay=1, max_delay=60)

props = Properties(PacketTypes.CONNECT)
props.SessionExpiryInterval = 900

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

Projetando para Clientes Offline

O enfileiramento ajuda em interrupções curtas, mas não deve ser a sua única ferramenta de confiabilidade. Um design robusto combina vários mecanismos:

  1. Use QoS 1 para comandos e eventos e QoS 0 para telemetria de alta frequência em que a próxima leitura substitui a anterior.
  2. Mantenha o session expiry realista. Longo o bastante para cobrir as interrupções típicas e curto o bastante para que dispositivos mortos não acumulem filas.
  3. Defina message expiry em comandos sensíveis ao tempo, para que um dispositivo que volta depois de uma hora não execute uma instrução desatualizada.
  4. Publique o estado como retained messages, para que qualquer cliente possa se ressincronizar instantaneamente sem depender de uma fila.
  5. Torne os handlers idempotentes. O QoS 1 pode entregar duplicatas após reconexões; inclua um ID de mensagem ou número de sequência no payload.
  6. Trate o Session Present = 0 como um evento normal, não como erro.
  7. Espere uma rajada na reconexão. Clientes que estavam offline podem receber muitas mensagens de uma vez; o Receive Maximum do MQTT 5 limita quantas mensagens não confirmadas chegam em paralelo.

Para entender as sessões em si, leia sessões persistentes MQTT e a flag clean session. Se você está começando agora, o tutorial de MQTT cobre primeiro o básico de publish/subscribe.

Resolvendo Problemas de Mensagens Offline Ausentes

  • Nada chega após a reconexão: confirme que o client ID é idêntico, que o Clean Start é false e, no MQTT 5, que o session expiry é diferente de zero.
  • Algumas mensagens chegam e outras não: compare o QoS de cada publish e da assinatura e verifique a expiração das mensagens.
  • Mensagens chegam duas vezes: é esperado com QoS 1 após uma confirmação interrompida; elimine as duplicatas na aplicação.
  • O Session Present é 0 inesperadamente: a sessão expirou, o client ID mudou ou o broker reiniciou.

Enfileire Mensagens Offline com a ConnectMQ

A ConnectMQ é um broker MQTT gerenciado que suporta sessões persistentes, session expiry e message expiry no MQTT 5.0, além de clientes MQTT 3.1.1. O plano Serverless Free suporta QoS até 1, que é tudo o que o enfileiramento offline exige, e o QoS 2 está disponível nos planos pagos. Crie o seu broker gratuito sem cartão de crédito, conecte-se com YOUR_USERNAME, YOUR_PASSWORD e YOUR_CLIENT_ID e execute o teste acima no seu próprio endpoint privado. Se estiver comparando provedores, veja o que avaliar em um broker MQTT na nuvem.

Perguntas frequentes

O MQTT armazena mensagens quando o assinante está offline?

Somente se o assinante tiver uma sessão persistente, já assinava um topic correspondente e o QoS efetivo for 1 ou 2. Caso contrário, a mensagem não é guardada para aquele cliente.

Por que minhas mensagens QoS 0 se perdem enquanto o dispositivo está offline?

Mensagens QoS 0 normalmente não são enfileiradas para sessões offline; a especificação torna isso opcional. Publique e assine com QoS 1 se a mensagem precisar sobreviver a uma desconexão.

Por quanto tempo um broker guarda mensagens offline?

Até a sessão expirar, um limite de fila ser atingido, a expiração da própria mensagem passar ou o broker reiniciar, caso as sessões fiquem em memória. Na ConnectMQ as sessões vivem em memória, e o servidor MQTT público limita o session expiry a 30 minutos.

As retained messages substituem o enfileiramento offline?

Não. Uma retained message entrega a um novo assinante o último valor de um topic, enquanto o enfileiramento offline entrega cada mensagem QoS 1 ou 2 que o cliente perdeu. A maioria dos sistemas usa as duas.

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.