Using QoS Policies¶
Quality of Service (QoS) policies control the behavior of DDS entities. This guide explains how to use and configure QoS policies in AstuteDDS.
What are QoS Policies?¶
QoS policies define non-functional properties like:
- Reliability: Guaranteed vs. best-effort delivery
- Durability: Whether late joiners get historical data
- History: How many samples to keep
- Deadline: Maximum time between samples
- Liveliness: How to detect inactive writers
- Ownership: Single vs. multiple writers
QoS Policy Categories¶
Data Delivery Policies¶
Control how data is delivered from writers to readers.
Reliability¶
Determines delivery guarantees:
#include <astutedds/dcps/qos.hpp>
// RELIABLE: Guaranteed delivery with retransmission
auto reliable_qos = astutedds::dcps::DataWriterQosBuilder()
.reliability(astutedds::dcps::ReliabilityQosPolicyKind::RELIABLE_RELIABILITY_QOS)
.build();
// BEST_EFFORT: No delivery guarantees, lower latency
auto besteffort_qos = astutedds::dcps::DataWriterQosBuilder()
.reliability(astutedds::dcps::ReliabilityQosPolicyKind::BEST_EFFORT_RELIABILITY_QOS)
.build();
When to use RELIABLE: - Commands and control messages - Financial transactions - Configuration updates - Any data that cannot be lost
When to use BEST_EFFORT: - High-frequency sensor data - Video/audio streams - Real-time telemetry - Data where latest value matters most
Durability¶
Controls late joiner behavior:
// VOLATILE: No historical data
auto volatile_qos = astutedds::dcps::DataWriterQosBuilder()
.durability(astutedds::dcps::DurabilityQosPolicyKind::VOLATILE_DURABILITY_QOS)
.build();
// TRANSIENT_LOCAL: Late joiners get last samples
auto transient_qos = astutedds::dcps::DataWriterQosBuilder()
.durability(astutedds::dcps::DurabilityQosPolicyKind::TRANSIENT_LOCAL_DURABILITY_QOS)
.build();
// TRANSIENT: Survives process restart
auto transient_persistent_qos = astutedds::dcps::DataWriterQosBuilder()
.durability(astutedds::dcps::DurabilityQosPolicyKind::TRANSIENT_DURABILITY_QOS)
.build();
// PERSISTENT: Stored in database
auto persistent_qos = astutedds::dcps::DataWriterQosBuilder()
.durability(astutedds::dcps::DurabilityQosPolicyKind::PERSISTENT_DURABILITY_QOS)
.build();
Durability levels:
| Level | Late Joiners | Process Restart | Database |
|---|---|---|---|
| VOLATILE | ❌ No data | ❌ Lost | ❌ No |
| TRANSIENT_LOCAL | ✅ Last samples | ❌ Lost | ❌ No |
| TRANSIENT | ✅ Last samples | ✅ Survives | ⚠️ Filesystem |
| PERSISTENT | ✅ All samples | ✅ Survives | ✅ Database |
History¶
Controls sample retention:
// KEEP_LAST: Keep only last N samples per instance
auto keep_last_qos = astutedds::dcps::DataWriterQosBuilder()
.history(astutedds::dcps::HistoryQosPolicyKind::KEEP_LAST_HISTORY_QOS, 10)
.build();
// KEEP_ALL: Keep all samples (up to resource limits)
auto keep_all_qos = astutedds::dcps::DataWriterQosBuilder()
.history(astutedds::dcps::HistoryQosPolicyKind::KEEP_ALL_HISTORY_QOS)
.build();
Trade-offs: - KEEP_LAST(n): Bounded memory, may lose old samples - KEEP_ALL: Unbounded memory (constrained by resource limits)
Data Timing Policies¶
Control temporal aspects of data delivery.
Deadline¶
Maximum time between sample updates:
using namespace std::chrono_literals;
// Expect updates at least every 1 second
auto deadline_qos = astutedds::dcps::DataWriterQosBuilder()
.deadline(1s)
.build();
// Reader expects same deadline
auto reader_qos = astutedds::dcps::DataReaderQosBuilder()
.deadline(1s)
.build();
Use cases: - Periodic sensor data (must arrive every X ms) - Heartbeat monitoring - Time-critical state updates
Callback on missed deadline:
reader->set_listener(
[](const astutedds::dcps::RequestedDeadlineMissedStatus& status) {
std::cout << "Deadline missed! " << status.total_count << " times\n";
}
);
Liveliness¶
Detects inactive writers:
// AUTOMATIC: DDS manages liveliness
auto auto_liveliness = astutedds::dcps::DataWriterQosBuilder()
.liveliness(
astutedds::dcps::LivelinessQosPolicyKind::AUTOMATIC_LIVELINESS_QOS,
3s // lease duration
)
.build();
// MANUAL_BY_PARTICIPANT: Application asserts participant liveliness
auto manual_participant = astutedds::dcps::DataWriterQosBuilder()
.liveliness(
astutedds::dcps::LivelinessQosPolicyKind::MANUAL_BY_PARTICIPANT_LIVELINESS_QOS,
5s
)
.build();
// MANUAL_BY_TOPIC: Application asserts per-writer liveliness
auto manual_topic = astutedds::dcps::DataWriterQosBuilder()
.liveliness(
astutedds::dcps::LivelinessQosPolicyKind::MANUAL_BY_TOPIC_LIVELINESS_QOS,
5s
)
.build();
Asserting liveliness manually:
// For MANUAL_BY_PARTICIPANT
participant->assert_liveliness();
// For MANUAL_BY_TOPIC
writer->assert_liveliness();
Data Availability Policies¶
Ownership¶
Controls multiple writers to the same instance:
// SHARED: All writers can update (default)
auto shared_ownership = astutedds::dcps::DataWriterQosBuilder()
.ownership(astutedds::dcps::OwnershipQosPolicyKind::SHARED_OWNERSHIP_QOS)
.build();
// EXCLUSIVE: Highest strength writer wins
auto exclusive_ownership = astutedds::dcps::DataWriterQosBuilder()
.ownership(astutedds::dcps::OwnershipQosPolicyKind::EXCLUSIVE_OWNERSHIP_QOS)
.ownership_strength(100) // Higher = higher priority
.build();
EXCLUSIVE ownership example:
// Primary writer (high strength)
auto primary_writer_qos = astutedds::dcps::DataWriterQosBuilder()
.ownership(astutedds::dcps::OwnershipQosPolicyKind::EXCLUSIVE_OWNERSHIP_QOS)
.ownership_strength(200)
.build();
// Backup writer (low strength)
auto backup_writer_qos = astutedds::dcps::DataWriterQosBuilder()
.ownership(astutedds::dcps::OwnershipQosPolicyKind::EXCLUSIVE_OWNERSHIP_QOS)
.ownership_strength(100)
.build();
// Reader only sees samples from primary (strength 200)
// If primary fails, reader switches to backup
Resource Management Policies¶
Resource Limits¶
Control memory usage:
auto resource_limits = astutedds::dcps::DataWriterQosBuilder()
.resource_limits(
1000, // max_samples
100, // max_instances
10 // max_samples_per_instance
)
.build();
Parameters:
- max_samples: Total samples across all instances
- max_instances: Maximum number of different keys
- max_samples_per_instance: Samples per key
User Data Policies¶
Attach metadata to entities:
// Attach user data to participant
std::vector<uint8_t> participant_data = {'A', 'p', 'p', '1'};
auto participant_qos = astutedds::dcps::DomainParticipantQosBuilder()
.user_data(participant_data)
.build();
// Attach group data to publisher
std::vector<uint8_t> group_data = {'S', 'e', 'n', 's', 'o', 'r', 's'};
auto publisher_qos = astutedds::dcps::PublisherQosBuilder()
.group_data(group_data)
.build();
// Attach topic data
std::vector<uint8_t> topic_data = {'v', '1', '.', '0'};
auto topic_qos = astutedds::dcps::TopicQosBuilder()
.topic_data(topic_data)
.build();
QoS Policy Compatibility¶
For communication to occur, QoS policies must be compatible:
RxO (Requested vs. Offered) Policies¶
Some policies follow "Requested vs. Offered" semantics:
| Policy | Rule | Example |
|---|---|---|
| Reliability | Requested ≤ Offered | Reader RELIABLE ← Writer RELIABLE ✅ Reader RELIABLE ← Writer BEST_EFFORT ❌ |
| Durability | Requested ≤ Offered | Reader TRANSIENT_LOCAL ← Writer TRANSIENT_LOCAL ✅ Reader TRANSIENT_LOCAL ← Writer VOLATILE ❌ |
| Deadline | Offered ≤ Requested | Writer 1s deadline → Reader 2s deadline ✅ Writer 2s deadline → Reader 1s deadline ❌ |
| Liveliness | Offered ≤ Requested | Writer 1s liveliness → Reader 2s lease ✅ |
Example: Compatible QoS¶
// Writer offers RELIABLE, TRANSIENT_LOCAL
auto writer_qos = astutedds::dcps::DataWriterQosBuilder()
.reliability(astutedds::dcps::ReliabilityQosPolicyKind::RELIABLE_RELIABILITY_QOS)
.durability(astutedds::dcps::DurabilityQosPolicyKind::TRANSIENT_LOCAL_DURABILITY_QOS)
.build();
// Reader requests RELIABLE, TRANSIENT_LOCAL - Compatible! ✅
auto reader_qos = astutedds::dcps::DataReaderQosBuilder()
.reliability(astutedds::dcps::ReliabilityQosPolicyKind::RELIABLE_RELIABILITY_QOS)
.durability(astutedds::dcps::DurabilityQosPolicyKind::TRANSIENT_LOCAL_DURABILITY_QOS)
.build();
Example: Incompatible QoS¶
// Writer offers BEST_EFFORT
auto writer_qos = astutedds::dcps::DataWriterQosBuilder()
.reliability(astutedds::dcps::ReliabilityQosPolicyKind::BEST_EFFORT_RELIABILITY_QOS)
.build();
// Reader requests RELIABLE - Incompatible! ❌
auto reader_qos = astutedds::dcps::DataReaderQosBuilder()
.reliability(astutedds::dcps::ReliabilityQosPolicyKind::RELIABLE_RELIABILITY_QOS)
.build();
// Result: Endpoints won't match, no communication
Common QoS Patterns¶
Pattern 1: Real-Time Sensor Data¶
High-frequency data where latest value matters:
auto sensor_qos = astutedds::dcps::DataWriterQosBuilder()
.reliability(astutedds::dcps::ReliabilityQosPolicyKind::BEST_EFFORT_RELIABILITY_QOS)
.durability(astutedds::dcps::DurabilityQosPolicyKind::VOLATILE_DURABILITY_QOS)
.history(astutedds::dcps::HistoryQosPolicyKind::KEEP_LAST_HISTORY_QOS, 1)
.build();
Pattern 2: Command and Control¶
Critical messages that must be delivered:
auto command_qos = astutedds::dcps::DataWriterQosBuilder()
.reliability(astutedds::dcps::ReliabilityQosPolicyKind::RELIABLE_RELIABILITY_QOS)
.durability(astutedds::dcps::DurabilityQosPolicyKind::TRANSIENT_LOCAL_DURABILITY_QOS)
.history(astutedds::dcps::HistoryQosPolicyKind::KEEP_ALL_HISTORY_QOS)
.build();
Pattern 3: State Synchronization¶
Current state for late joiners:
auto state_qos = astutedds::dcps::DataWriterQosBuilder()
.reliability(astutedds::dcps::ReliabilityQosPolicyKind::RELIABLE_RELIABILITY_QOS)
.durability(astutedds::dcps::DurabilityQosPolicyKind::TRANSIENT_LOCAL_DURABILITY_QOS)
.history(astutedds::dcps::HistoryQosPolicyKind::KEEP_LAST_HISTORY_QOS, 1)
.build();
Pattern 4: Event Stream¶
Sequence of events that must all be received:
auto event_qos = astutedds::dcps::DataWriterQosBuilder()
.reliability(astutedds::dcps::ReliabilityQosPolicyKind::RELIABLE_RELIABILITY_QOS)
.durability(astutedds::dcps::DurabilityQosPolicyKind::VOLATILE_DURABILITY_QOS)
.history(astutedds::dcps::HistoryQosPolicyKind::KEEP_ALL_HISTORY_QOS)
.build();
Pattern 5: Failover System¶
High-availability with exclusive ownership:
// Primary system
auto primary_qos = astutedds::dcps::DataWriterQosBuilder()
.reliability(astutedds::dcps::ReliabilityQosPolicyKind::RELIABLE_RELIABILITY_QOS)
.ownership(astutedds::dcps::OwnershipQosPolicyKind::EXCLUSIVE_OWNERSHIP_QOS)
.ownership_strength(200)
.liveliness(
astutedds::dcps::LivelinessQosPolicyKind::MANUAL_BY_TOPIC_LIVELINESS_QOS,
1s
)
.build();
// Backup system
auto backup_qos = astutedds::dcps::DataWriterQosBuilder()
.reliability(astutedds::dcps::ReliabilityQosPolicyKind::RELIABLE_RELIABILITY_QOS)
.ownership(astutedds::dcps::OwnershipQosPolicyKind::EXCLUSIVE_OWNERSHIP_QOS)
.ownership_strength(100) // Lower strength
.liveliness(
astutedds::dcps::LivelinessQosPolicyKind::MANUAL_BY_TOPIC_LIVELINESS_QOS,
1s
)
.build();
Complete Example¶
Here's a complete example showing QoS configuration:
#include <astutedds/dcps/domain_participant.hpp>
#include <astutedds/dcps/qos.hpp>
#include "SensorData_TypeSupport.hpp"
int main() {
using namespace astutedds::dcps;
// Create participant
auto participant = DomainParticipantFactory::create_participant(0);
// Configure topic QoS
auto topic_qos = TopicQosBuilder()
.reliability(ReliabilityQosPolicyKind::RELIABLE_RELIABILITY_QOS)
.durability(DurabilityQosPolicyKind::TRANSIENT_LOCAL_DURABILITY_QOS)
.build();
// Create topic
auto topic = participant->create_topic<SensorData>(
"SensorTopic",
topic_qos
);
// Configure writer QoS
auto writer_qos = DataWriterQosBuilder()
.reliability(ReliabilityQosPolicyKind::RELIABLE_RELIABILITY_QOS)
.durability(DurabilityQosPolicyKind::TRANSIENT_LOCAL_DURABILITY_QOS)
.history(HistoryQosPolicyKind::KEEP_LAST_HISTORY_QOS, 10)
.deadline(std::chrono::seconds(1))
.resource_limits(1000, 100, 10)
.build();
// Create writer
auto publisher = participant->create_publisher();
auto writer = publisher->create_datawriter(topic, writer_qos);
// Configure reader QoS (must be compatible)
auto reader_qos = DataReaderQosBuilder()
.reliability(ReliabilityQosPolicyKind::RELIABLE_RELIABILITY_QOS)
.durability(DurabilityQosPolicyKind::TRANSIENT_LOCAL_DURABILITY_QOS)
.history(HistoryQosPolicyKind::KEEP_LAST_HISTORY_QOS, 20)
.deadline(std::chrono::seconds(2)) // More lenient than writer
.build();
// Create reader
auto subscriber = participant->create_subscriber();
auto reader = subscriber->create_datareader(topic, reader_qos);
// Publish data
SensorData data;
data.temperature = 25.5;
data.humidity = 60.0;
writer->write(data);
return 0;
}
QoS Best Practices¶
- Start with defaults: Use
DATAWRITER_QOS_DEFAULTinitially - Match carefully: Ensure writer/reader QoS policies are compatible
- Test combinations: Verify QoS behavior in your specific scenario
- Monitor resource usage: KEEP_ALL can consume unbounded memory
- Use RELIABLE sparingly: Only for data that must not be lost
- Set appropriate limits: Configure resource limits to prevent OOM
- Consider late joiners: Use TRANSIENT_LOCAL for state data
- Profile for performance: BEST_EFFORT has lower latency
Next Steps¶
- Review QoS Examples for more code samples
- Test QoS with the Shapes Demo
- Learn about IDL Compiler for type generation
- Explore DDS Concepts for detailed theory