Le message expiry interval MQTT est une propriété MQTT 5 qui indique au broker pendant combien de secondes un message reste valide. Une fois ce délai écoulé, le broker jette le message au lieu de le livrer à un client qui se reconnecte en retard. Dans cet article, vous apprendrez précisément comment fonctionne l'expiration, vous la verrez écarter une commande périmée lors d'un test réel, et vous obtiendrez une check-list pour choisir les valeurs d'expiration de votre propre système.
Le problème : des commandes qui arrivent trop tard
Imaginez un appareil abonné en QoS 1 avec une session persistante. Un opérateur envoie « ouvrir le portail » pendant que l'appareil est hors ligne. Le broker met la commande en file, car la session est toujours active. Deux heures plus tard, l'appareil se reconnecte via une liaison cellulaire instable et le broker livre consciencieusement « ouvrir le portail ». Plus personne n'attend devant le portail.
Avant MQTT 5, aucun mécanisme du protocole ne permettait d'éviter cela. Les développeurs ajoutaient des horodatages dans les payloads en espérant que chaque appareil les vérifie. MQTT 5 a intégré la solution au protocole avec le message expiry interval, une propriété du paquet PUBLISH. C'est l'une des fonctionnalités de MQTT 5 les plus utiles pour quiconque pilote des équipements physiques.
Comment fonctionne le message expiry interval MQTT
L'éditeur définit la propriété en secondes, sous forme d'entier sur quatre octets. Le broker applique ensuite ces règles :
- À l'arrivée du message, le broker enregistre l'heure.
- Si le message est mis en file pour un abonné hors ligne disposant d'une session persistante et que l'intervalle s'écoule avant la livraison, le broker le supprime.
- Lorsque le broker livre le message, il réécrit la propriété avec le temps restant. Un message publié avec 60 secondes et livré 45 secondes plus tard arrive avec un intervalle de 15.
- Si le message est retained, la copie retained expire aussi. Passé l'intervalle, les nouveaux abonnés ne la reçoivent plus.
- Si la propriété est absente, le message n'expire jamais, ce qui correspond au comportement de MQTT 3.1.1.
La quatrième règle rend l'expiration utile au-delà des commandes. Une bannière retained « mode maintenance actif » peut être configurée pour expirer d'elle-même, afin qu'un indicateur oublié ne traîne pas pendant des semaines.
| Type de message | Expiration suggérée | Justification |
|---|---|---|
| Commande d'actionneur (ouvrir, démarrer, arrêter) | 5 à 60 s | Valide uniquement tant qu'un opérateur surveille |
| Envoi de configuration | Heures à jours | Toujours utile lorsqu'un appareil se reconnecte plus tard |
| Télémétrie vers un consommateur persistant | Minutes | Les anciennes mesures perdent de leur valeur mais peuvent combler des trous |
| État temporaire retained | Durée de l'état | S'efface automatiquement |
| Notification d'alarme | Tant qu'elle reste exploitable | Évite les avalanches d'alarmes obsolètes |
Pourquoi l'expiration n'a d'effet qu'avec des sessions persistantes
L'expiration ne concerne que les messages qui attendent quelque part. Avec une session propre sans état stocké, un abonné déconnecté manque simplement les messages : il n'y a rien à faire expirer. L'expiration compte à deux endroits :
- Les files de session. Un client qui se connecte avec clean start à false et un session expiry interval supérieur à zéro voit ses messages QoS 1 et QoS 2 mis en file pendant qu'il est hors ligne. Consultez le session expiry interval MQTT, qui explique comment cette file est constituée.
- Le stockage retained. Un retained message doté d'une expiration est supprimé après l'intervalle.
Notez la différence entre les deux réglages d'expiration : le session expiry contrôle combien de temps le broker se souvient d'un client ; le message expiry contrôle combien de temps un message donné vaut la peine d'être livré. En général, vous voulez les deux.
Tester l'expiration des messages sur un broker réel
Nous allons utiliser le serveur MQTT public gratuit broker.connectmq.com, qui prend en charge MQTT 5 et des sessions allant jusqu'à 30 minutes. Il est réservé aux tests et aux prototypes, pas aux données de production. Utilisez votre propre préfixe de topic.
Étape 1 : créez une session persistante. Connectez-vous une fois avec clean start désactivé (-c), une session expiry de 600 secondes (-x 600) et la QoS 1, puis arrêtez avec Ctrl+C :
mosquitto_sub -V mqttv5 -h broker.connectmq.com -p 1883 -i exp-dev-m4t9 \
-c -x 600 -q 1 -t connectmq/demo/m4t9/gate/cmd -v
Étape 2 : pendant que l'abonné est hors ligne, publiez une commande qui expire au bout de 10 secondes et une autre qui dure 5 minutes :
mosquitto_pub -V mqttv5 -h broker.connectmq.com -p 1883 -i exp-op-m4t9 -q 1 \
-t connectmq/demo/m4t9/gate/cmd -m 'open (10s)' \
-D publish message-expiry-interval 10
mosquitto_pub -V mqttv5 -h broker.connectmq.com -p 1883 -i exp-op-m4t9 -q 1 \
-t connectmq/demo/m4t9/gate/cmd -m 'report-status (300s)' \
-D publish message-expiry-interval 300
Étape 3 : attendez au moins 20 secondes, puis reconnectez-vous avec exactement la même commande qu'à l'étape 1. Seul report-status (300s) arrive. La commande d'ouverture a expiré dans la file et n'a jamais été livrée. Refaites rapidement les étapes 2 et 3, en moins de 10 secondes, et les deux messages arrivent.
Définir l'expiration en Python et Node.js
Avec paho-mqtt 2.x, vous attachez un objet Properties à la publication. Le client doit utiliser MQTT 5 :
import json
import uuid
import paho.mqtt.client as mqtt
from paho.mqtt.properties import Properties
from paho.mqtt.packettypes import PacketTypes
client = mqtt.Client(
mqtt.CallbackAPIVersion.VERSION2,
client_id=f"op-{uuid.uuid4().hex[:8]}",
protocol=mqtt.MQTTv5,
)
client.connect("broker.connectmq.com", 1883, keepalive=30)
client.loop_start()
props = Properties(PacketTypes.PUBLISH)
props.MessageExpiryInterval = 30 # secondes
cmd = {"action": "open", "issuedBy": "operator-3"}
info = client.publish("connectmq/demo/m4t9/gate/cmd", json.dumps(cmd), qos=1, properties=props)
info.wait_for_publish()
client.loop_stop()
client.disconnect()
Côté réception, msg.properties contient MessageExpiryInterval avec les secondes restantes, qu'un appareil peut journaliser ou utiliser pour rejeter les commandes presque expirées.
Avec MQTT.js v5, la propriété se place dans les options de publication :
const mqtt = require("mqtt");
const client = mqtt.connect("mqtts://broker.connectmq.com:8883", {
clientId: "op-" + Math.random().toString(16).slice(2, 10),
protocolVersion: 5,
});
client.on("connect", () => {
client.publish(
"connectmq/demo/m4t9/gate/cmd",
JSON.stringify({ action: "close" }),
{ qos: 1, properties: { messageExpiryInterval: 30 } },
(err) => {
if (err) console.error(err);
client.end();
}
);
});
Pièges et dépannage
L'expiration est totalement ignorée. Vérifiez que l'éditeur et la connexion au broker utilisent bien MQTT 5. Un client 3.1.1 ne peut pas envoyer la propriété, et un abonné 3.1.1 reçoit le message sans elle.
Le message arrive quand même en retard. L'expiration empêche la livraison depuis la file du broker. Elle n'aide pas si le message se trouve déjà dans le tampon de l'appareil ou d'une passerelle intermédiaire. Les appareils qui exécutent des commandes doivent toujours comparer un horodatage du payload à leur horloge lorsque la sécurité est en jeu.
Les commandes expirent trop vite. Tenez compte de la latence du réseau et de la mise en file par le broker. Une expiration de 1 ou 2 secondes peut supprimer des commandes légitimes sur des liaisons lentes.
Un retained message a disparu. Si quelqu'un a publié la valeur retained avec une expiration, elle disparaît une fois l'intervalle écoulé. C'est souvent voulu ; vérifiez l'éditeur avant de conclure à une perte de données. Pour les bases du retained, consultez les retained messages MQTT.
Expiration ou QoS. La QoS détermine si un message est livré ; l'expiration détermine s'il vaut encore la peine de l'être. Un message QoS 1 avec expiration peut légitimement ne jamais arriver.
Combiner l'expiration avec d'autres garde-fous
L'expiration des messages est une couche de défense, pas toute la conception. Pour les commandes qui actionnent des équipements physiques, une configuration robuste combine généralement plusieurs mécanismes :
- Une expiration sur chaque commande pour que le broker supprime les commandes périmées des files.
- Un identifiant de commande et un horodatage d'émission dans le payload pour que l'appareil puisse rejeter tout ce qui dépasse son propre seuil, même si une passerelle l'a mis en tampon.
- Pas de flag retain sur les commandes, pour qu'un redémarrage ne rejoue jamais une ancienne instruction.
- Un topic d'acquittement sur lequel l'appareil indique s'il a exécuté ou rejeté la commande, idéalement avec le modèle requête-réponse MQTT.
- Des verrouillages sur l'appareil pour tout ce qui touche à la sécurité. Le réseau ne doit jamais être le seul rempart contre une action dangereuse.
Considérez l'expiration comme l'outil qui garde les files propres et rend les livraisons tardives rares, tandis que les vérifications côté appareil rendent les exécutions tardives impossibles.
L'expiration des messages sur ConnectMQ
ConnectMQ prend en charge MQTT 5.0 avec message expiry, session expiry, response topic et les autres propriétés MQTT 5 sur ses connexions MQTT 5.0. En production, connectez vos outils d'opérateur et vos appareils avec les identifiants du portail via TLS sur le port 8883 et appliquez une expiration à chaque topic de commande, par principe. Un broker MQTT managé se charge d'exploiter le stockage des sessions et les files, si bien que votre équipe n'a qu'à choisir des valeurs d'expiration judicieuses. Le tutoriel MQTT couvre le reste des fondamentaux.
Démarrer avec ConnectMQ
Créez gratuitement un broker sur app.connectmq.com avec le plan Serverless, sans carte bancaire. Connectez-vous en MQTT 5, ajoutez une expiration à votre première commande et testez-la avec un appareil qui se reconnecte en retard. L'exécuter sur un broker MQTT cloud vous évite de maintenir des serveurs pendant vos expérimentations.
Questions fréquentes
Quelle unité utilise le message expiry interval ?
La seconde, stockée sous forme d'entier non signé sur quatre octets. Si la propriété n'est pas définie, le message n'expire pas.
L'abonné voit-il la valeur d'expiration d'origine ?
Non. Le broker envoie le temps restant, ce qui permet à un abonné de savoir quelle durée de validité il reste à l'arrivée du message.
L'expiration des messages fonctionne-t-elle avec MQTT 3.1.1 ?
Non. C'est une propriété de MQTT 5. Avec MQTT 3.1.1, il faut un horodatage dans le payload que le destinataire vérifie lui-même.
Les retained messages peuvent-ils expirer ?
Oui. Un retained message publié avec un message expiry interval est retiré du stockage retained une fois l'intervalle écoulé.



