Offline & Retain
How CloudSignal's MQTT infrastructure handles offline message queuing and retained messages - built into the protocol, no extra systems required.
One of the hardest problems in real-time messaging is what happens when a client is not connected. Do messages disappear? Do you need a separate message queue? A database to persist undelivered messages? A background job to retry?
With most messaging approaches - raw WebSockets, HTTP polling, custom pub/sub - the answer is yes. You build and maintain all of that yourself.
CloudSignal is built on MQTT, where offline delivery and message retention are protocol-level features, not application-level afterthoughts. The broker handles offline queuing, message persistence, and replay - no additional infrastructure required.
Offline message queuing
When a client disconnects, the broker does not discard its subscriptions. If the client used a persistent session, the broker continues accepting messages on its behalf and queues them for delivery when the client reconnects.
How persistent sessions work
A client requests a persistent session by connecting with clean_start=false (MQTT 5) or clean_session=false (MQTT 3.1.1). This tells the broker:
- Remember my subscriptions - Even when I disconnect, keep my subscription list
- Queue messages for me - Any message matching my subscriptions while I am offline should be stored
- Replay on reconnect - When I come back with the same client ID, deliver everything I missed
The client does not need to re-subscribe after reconnection. The broker restores the session state and delivers queued messages in order.
Session expiry
MQTT 5 introduced the Session Expiry Interval, giving you control over how long the broker holds a session after disconnect:
| Expiry Setting | Behavior | Use Case |
|---|---|---|
0 | Session removed immediately | Stateless clients, dashboards |
3600 (1 hour) | Session held for 1 hour | Mobile apps with brief disconnects |
86400 (1 day) | Session held for 24 hours | IoT devices with intermittent connectivity |
max | Session persists indefinitely | Critical devices that may be offline for days |
Choose an expiry that matches your reconnection window. A mobile app that reconnects within minutes needs a short interval. A sensor in a remote location that may go offline for hours needs a longer one. Longer intervals consume more broker resources, so set them intentionally.
Why MQTT's approach is better
Building offline delivery on other transports means assembling multiple systems:
With a custom approach, you maintain:
- A message queue (Redis, RabbitMQ, SQS) to buffer undelivered messages
- A persistence layer (database) to survive restarts
- A delivery tracker to know which clients received which messages
- Retry logic with backoff and deduplication
- Connection state management to detect who is online
With CloudSignal, the broker is the queue, the persistence layer, the delivery tracker, and the connection manager. It is a single system that handles offline delivery as a first-class capability because the MQTT protocol was designed for unreliable networks from day one.
Retained messages
Retained messages solve a different problem: what should a new subscriber see when it first connects?
Without retained messages, a subscriber only receives messages published after it subscribes. If an agent updates its presence every 30 seconds and a new dashboard client subscribes, it has to wait up to 30 seconds before seeing the agent's state.
A retained message is stored by the broker and immediately delivered to any new subscriber on that topic.
How retained messages work
- A publisher sends a message with the retain flag set to
true - The broker stores this message as the retained message for that topic
- The broker delivers the message to current subscribers normally
- When any new subscriber subscribes to that topic, it immediately receives the retained message
- A new retained publish to the same topic replaces the stored message
- Publishing an empty payload with
retain=trueclears the retained message
Only one retained message is stored per topic. It always reflects the most recent retained publish.
Practical uses of retained messages
| Use Case | Topic | Retained Payload |
|---|---|---|
| Agent presence | presence/{agent_id} | {"online": true, "load": 0.42} |
| Configuration | config/{service}/settings | Current configuration JSON |
| Latest agent state | agents/{agent_id}/state | {"status": "idle", "last_task": "task_8a3"} |
| Feature flags | flags/{feature} | {"enabled": true} |
| System announcements | system/maintenance | {"message": "Scheduled maintenance at 02:00 UTC"} |
Retained messages are especially valuable for status and configuration topics. New clients get the current state immediately instead of waiting for the next update cycle. This eliminates the "cold start" problem where new subscribers have no data.
Offline queuing + retain together
These two features complement each other:
- Offline queuing ensures a disconnected client does not miss messages published while it was away
- Retained messages ensure a newly subscribing client gets the latest state immediately
Together, they cover both scenarios: clients that were connected and went offline, and clients that are connecting for the first time. No application-level caching, no "fetch initial state" API call, no synchronization logic.
Clean start vs. persistent sessions
The clean_start flag on connection determines which behavior you get:
| Setting | Subscriptions | Offline Queue | Retained Messages |
|---|---|---|---|
clean_start=true | Cleared on connect | No queuing | Still received on subscribe |
clean_start=false | Restored from session | Messages queued while offline | Still received on subscribe |
Note that retained messages are delivered regardless of session type - they are a property of the topic, not the session. Offline queuing requires a persistent session.
Next steps
- Persistent sessions guide - Configure session persistence for your clients
- QoS levels - How delivery guarantees interact with offline queuing
- Pub/Sub & topics - Topic structure and subscription patterns
QoS levels
How CloudSignal leverages MQTT's built-in delivery guarantees to ensure your messages arrive - and how to choose the right level for your use case.
Developer & AI ready
REST API, JavaScript and Python SDKs, and a CLI - all designed to work with your favorite coding agent and development workflow.