Sometime in the past, there was a challenge to monitor oil pipelines spanning vast, remote areas. These areas had unreliable, low-bandwidth networks. Plus, the monitoring devices ran on batteries, making energy conservation essential— constant communication or high network usage wasn't practical.
A wire protocol that caters to these challenges was needed and the answer was MQTT. MQTT was designed with specific features that are tailored to the challenges at hand - features like:
- Quality of Service (QoS)
- Last Will and Testament
- Retained Messages
This blog will focus on the MQTT retained messages feature and to begin…
What are MQTT retained messages?
In MQTT, when a publisher sends a message to a topic, the broker broadcasts it to all the clients subscribed to that topic. But if no clients are subscribed to the topic when a message is sent, the broker discards the message. Consequently, new or reconnecting clients will never receive the message — this is where retained messages come in.
The retained messages feature allows MQTT brokers to persist
the last known message on a topic. You can enable this feature
by sending a
PUBLISH
packet to the broker with the
retain
flag set to true
(retain=1).
When the broker sees this flag, it knows
to persist the message in the topic it’s been published to.
That way, new or reconnecting subscribers get that last
message when they join the topic.
Because an MQTT topic can only hold one message at a time, even with
retain=true
the broker can only keep the latest message on that topic. For example,
if you publish three messages with
retain=true,
the second message will override the first and third will override the second.
However, keep in mind that a retained message is not necessarily the latest value published to a topic, it is simply the most recent message with the retained flag set to true published to that topic.
In more concrete terms, let’s say you first publish
message A
with
retain=true
and next you publish
message B
with
retain=false
— even though
message B
is the most recent message, new and reconnecting clients
subscribed to that topic would only receive
message A.
Side note:
Publishing a message with the
retain
flag set to false
(retain=0)
or without the retain flag at all, tells the broker to not retain
the message in that topic. As a result, only clients who are
currently connected and subscribed to that topic will get the message.
Now that you know what a retained message is, you are probably wondering …
Why retain a message?
- As stated earlier, MQTT was designed to also do well in areas with unreliable networks — in such scenarios, devices connected to an MQTT broker can disconnect and reconnect unexpectedly. Retaining the last known message on a topic would allow any device coming online after a downtime to immediately get the latest message without waiting for a new update.
- Furthermore, retained messages play a role in providing newly-subscribed clients with instant status updates upon subscribing to a topic. As a result, they don't have to wait idly for new updates from the publishers. This is particularly advantageous in scenarios where it is important to deliver real-time updates to clients.
- You might also want to retain a message in a topic when the payload does not change very often and every new subscriber to that topic would need that same payload.
Retained messages examples
Let’s consider two examples:
- Publishing a retained message to a topic
- Deleting a retained message from a topic
Publishing a retained message
Most of the MQTT client libraries out there provide a super easy way to enable the
retain
flag. In the code snippet below we are using the
MQTT.js client library
where we publish a retained message by passing the
retain: true
flag as an option.
function pubSub() {
const client = mqtt.connect(
clientSettings.host,
clientSettings.options
)
client.on('connect', function () {
console.log("[✅] Connection over channel established")
client.publish('topic/temp', 'Retained Message', { retain: true }, function(err) {
if (!err) {
console.log('[📥] Message sent to queue');
}
});
client.subscribe('topic/temp', function (err) {
if (err) {
console.log('Could not subscribe: ', err)
}
});
})
client.on('message', function (topic, message) {
console.log(topic)
console.log(message.toString())
})
client.on('error', function(err) {
console.log('ERROR: ', err);
client.end();
});
}
Deleting a retained message from a topic
If for whatever reason you’d like to delete a message previously retained
on a topic, you can do this by explicitly publishing a zero bytes message
to that topic with the
retain
flag set to
true.
We do this by setting the payload to
null
in the code snippet below.
client.publish('topic/temp', null, { retain: true }, function(err) {
if (!err) {
console.log('[📥] Message sent to queue');
}
});
Wrap up
As we’ve seen, by enabling messages to persist on a topic, the retain message feature ensures that new or reconnecting devices receive the last known message without delay. This is particularly valuable in scenarios where real-time information is crucial or the payload does not change frequently.
The examples provided in this blog, including how to publish and delete retained messages, highlight the ease with which this feature can be implemented using most MQTT client libraries.
Note: RabbitMQ supports MQTT 3.1.1 in all its versions as well as MQTT 5.0 in versions >= 3.13. You can create a free RabbitMQ instance on CloudAMQP and test out MQTT.
We’d be happy to hear from you! Please leave your suggestions, questions, or feedback in the comment section or contact us at contact@cloudamqp.com