Konkrete Policy-Kombinationen für die häufigsten Production-Setups. Jedes Rezept zeigt die relevanten Policies, einen Code-Snippet und die typischen Trade-Offs.
1 · Telemetry-Sink — Fire-and-Forget
Wann: Hochfrequenz-Sensoren (≥100 Hz), Verlust von Einzel-Samples tolerierbar, Konsumenten kommen und gehen.
let writer_qos = DataWriterQos {
reliability: ReliabilityQosPolicy {
kind: ReliabilityKind::BestEffort,
..Default::default()
},
durability: DurabilityQosPolicy {
kind: DurabilityKind::Volatile,
},
history: HistoryQosPolicy {
kind: HistoryKind::KeepLast,
depth: 1,
},
..Default::default()
};
▶ Runnable example: qos-cookbook
Trade-Off: Kein ACK-Verkehr, kein Retransmit. Late-Joiner sehen nichts. Wer das Sample verliert, hat es verloren.
2 · Late-Joiner mit Last-Value-Cache
Wann: Config-/State-Topics (Setpoints, Modes), Konsumenten starten asynchron und müssen den letzten Wert beim Beitritt sehen.
let writer_qos = DataWriterQos {
reliability: ReliabilityQosPolicy {
kind: ReliabilityKind::Reliable,
max_blocking_time: Duration::from_millis(100),
},
durability: DurabilityQosPolicy {
kind: DurabilityKind::TransientLocal,
},
history: HistoryQosPolicy {
kind: HistoryKind::KeepLast,
depth: 1,
},
..Default::default()
};
▶ Runnable example: qos-cookbook
Trade-Off: Writer hält 1 Sample pro Instance im Cache; Speicher steigt mit Instance-Anzahl. Reader-Side DurabilityKind::TransientLocal muss matchen, sonst kein Cache-Replay.
3 · Exclusive-Ownership Failover
Wann: Hot-Standby-Schreiber (Primary + Backup), nur ein Writer pro Instance darf zeitgleich publizieren.
let primary_qos = DataWriterQos {
ownership: OwnershipQosPolicy {
kind: OwnershipKind::Exclusive,
},
ownership_strength: OwnershipStrengthQosPolicy { value: 100 },
liveliness: LivelinessQosPolicy {
kind: LivelinessKind::ManualByTopic,
lease_duration: Duration::from_secs(1),
},
..Default::default()
};
// Backup: gleiche Topic + ownership=Exclusive, strength=50
▶ Runnable example: qos-cookbook
Trade-Off: Lease-Duration definiert Failover-Latenz (Sekunden). Beide Writer müssen assert_liveliness() in der App ausführen.
4 · Hard-Realtime — Deadline + LatencyBudget
Wann: Control-Loops mit harten Zyklus-Garantien, deadline-misses sind Fehler-Signale, latenz-Budget zur Hinweis-Optimierung.
let reader_qos = DataReaderQos {
deadline: DeadlineQosPolicy {
period: Duration::from_millis(10), // 100 Hz
},
latency_budget: LatencyBudgetQosPolicy {
duration: Duration::from_micros(500),
},
reliability: ReliabilityQosPolicy {
kind: ReliabilityKind::Reliable,
max_blocking_time: Duration::from_millis(1),
},
history: HistoryQosPolicy {
kind: HistoryKind::KeepLast,
depth: 4, // 40 ms headroom
},
..Default::default()
};
▶ Runnable example: qos-cookbook
Trade-Off: RequestedDeadlineMissedStatus muss vom Reader-Listener gehandelt werden. LatencyBudget ist ein Hint, kein Match-Effekt — wird vom Transport-Scheduler ausgewertet.
5 · Partitioned Multi-Tenant Topics
Wann: Mehrere Tenants teilen sich ein Topic-Set, dürfen sich aber nicht gegenseitig matchen (z.B. customer-A/odom vs. customer-B/odom).
let publisher_qos = PublisherQos {
partition: PartitionQosPolicy {
names: vec!["customer-A".into()],
},
..Default::default()
};
// Subscriber-Side: partition = ["customer-A"] oder ["customer-*"] (Pattern)
▶ Runnable example: qos-cookbook
Trade-Off: Partition matched über String-Comparison (mit POSIX-fnmatch-Pattern). Discovery-Verkehr läuft trotzdem über die gleiche Domain — Partition ist Match-Filter, keine Network-Isolation.