Reliability QoS Policy
The Reliability policy controls whether data delivery is guaranteed or best-effort.
Values
| Value | Description | Use Case |
|---|---|---|
BestEffort | Fire and forget, no retransmission | Sensor data, video streaming |
Reliable | Guaranteed delivery with ACK/NACK | Commands, state synchronization |
Best Effort
Samples are sent once without acknowledgment. If a sample is lost due to network issues, it is not retransmitted.
use hdds::prelude::*;
let qos = DataWriterQos::default()
.reliability(Reliability::BestEffort);
let writer = publisher.create_writer_with_qos(&topic, qos)?;
Characteristics:
- Lowest latency (no ACK overhead)
- No blocking on write
- Samples may be lost
- No memory accumulation for retransmission
Reliable
Samples are acknowledged by readers. Lost samples trigger NACK-based retransmission.
use hdds::prelude::*;
use std::time::Duration;
let qos = DataWriterQos::default()
.reliability(Reliability::Reliable {
max_blocking_time: Duration::from_secs(1),
});
let writer = publisher.create_writer_with_qos(&topic, qos)?;
Parameters:
max_blocking_time: Maximum timewrite()can block waiting for buffer space
Characteristics:
- Guaranteed delivery (if reader is reachable)
- Higher latency due to ACK/NACK protocol
- Writer may block if reader is slow
- Memory used for retransmission buffer
Protocol Details
RTPS Reliable Protocol
Heartbeat Mechanism
Writers periodically send HEARTBEAT messages announcing available sequence numbers. Readers respond with ACKNACK indicating which samples they need.
| Parameter | Default | Description |
|---|---|---|
| Heartbeat period | 100 ms | Time between heartbeats |
| NACK response delay | 10 ms | Delay before sending NACK |
| Max retransmissions | Unlimited | Retries until timeout |
Compatibility Rules
Writers and readers must have compatible reliability settings:
| Writer | Reader | Match? |
|---|---|---|
| RELIABLE | RELIABLE | ✅ Yes |
| RELIABLE | BEST_EFFORT | ✅ Yes |
| BEST_EFFORT | BEST_EFFORT | ✅ Yes |
| BEST_EFFORT | RELIABLE | ❌ No Match |
Incompatibility
A BEST_EFFORT writer cannot satisfy a RELIABLE reader. The reader expects acknowledgments that the writer won't send.
Performance Considerations
Best Effort
// High-frequency sensor data (1000+ Hz)
let qos = DataWriterQos::default()
.reliability(Reliability::BestEffort)
.history(History::KeepLast { depth: 1 });
- Latency: ~100 μs
- Throughput: Up to 4M msg/s
- Memory: Minimal (no retransmission buffer)
Reliable
// Critical commands requiring guaranteed delivery
let qos = DataWriterQos::default()
.reliability(Reliability::Reliable {
max_blocking_time: Duration::from_millis(100),
})
.history(History::KeepLast { depth: 100 });
- Latency: ~500 μs - 10 ms (depends on network)
- Throughput: Up to 100K msg/s
- Memory: History depth × sample size
Blocking Behavior
With Reliable, the write() call may block:
// Non-blocking write with timeout
match writer.write(&sample) {
Ok(()) => println!("Sample sent"),
Err(Error::Timeout) => println!("Buffer full, sample dropped"),
Err(e) => return Err(e),
}
To avoid blocking:
- Increase
max_blocking_timefor bursty traffic - Use larger history depth to buffer samples
- Ensure readers keep up with writer rate
Examples
Telemetry (Best Effort)
// High-rate sensor data where occasional loss is acceptable
let writer_qos = DataWriterQos::default()
.reliability(Reliability::BestEffort)
.history(History::KeepLast { depth: 1 });
let reader_qos = DataReaderQos::default()
.reliability(Reliability::BestEffort);
Commands (Reliable)
// Robot commands that must not be lost
let writer_qos = DataWriterQos::default()
.reliability(Reliability::Reliable {
max_blocking_time: Duration::from_secs(5),
})
.history(History::KeepAll);
let reader_qos = DataReaderQos::default()
.reliability(Reliability::Reliable);
Mixed System
// Writer offers reliable (stronger guarantee)
let writer_qos = DataWriterQos::default()
.reliability(Reliability::Reliable {
max_blocking_time: Duration::from_secs(1),
});
// Reader A accepts best-effort (compatible)
let reader_a_qos = DataReaderQos::default()
.reliability(Reliability::BestEffort);
// Reader B requires reliable (compatible)
let reader_b_qos = DataReaderQos::default()
.reliability(Reliability::Reliable);
Next Steps
- Durability - Data persistence for late joiners
- History - Sample buffering depth