docs(managed): document lifecycle outcome contracts

Document terminal group events, structured failure decisions, explicit static versus dynamic completion, empty desired-set behavior, bounded join history, dropped-event detection, and missed-slot pacing.
This commit is contained in:
Nils Andreas Svee committed 2026-07-28 01:04:44 +07:00
1 parent 6adec06442
commit 8ea4c2f8a4
3 files changed
+36 -1

No files matched your search

+18
View File
@@ -217,6 +217,24 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
The client library emits structured events for session lifecycle, sent probes, successful replies, loss, duplicates, late replies, warnings, and shutdown. The client library emits structured events for session lifecycle, sent probes, successful replies, loss, duplicates, late replies, warnings, and shutdown.
For shared-socket multi-target integrations, `ManagedClientGroup` publishes
`ManagedGroupEvent::TargetFinished` exactly once for every terminal target
incarnation, including open/runtime failures, removal, cancellation, no-test
completion, and peer closure. Consumers can use `ManagedTargetEndReason` and
`ManagedTargetFailureKind` for outcome and exit decisions without parsing
diagnostic text.
`ManagedGroupCompletionPolicy::AllTargetsComplete` supports finite static
groups. `ExplicitCancellation` supports long-lived controllers; replacing the
desired set with an empty vector removes current targets but leaves the group
idle and ready for a later `update_targets` call. `join()` reports aggregate
outcome counts and retains only the 256 most recent target outcomes, so
long-running target churn remains bounded.
Managed event subscriptions remain bounded and nonblocking. When using a
dropping overflow policy, check `EventSubscription::dropped_events()` before
trusting a complete statistical summary.
## Binaries and features ## Binaries and features
| Build | Binaries | | Build | Binaries |
+16
View File
@@ -97,6 +97,10 @@ pub struct ManagedTargetConfig {
} }
/// Group send pacing strategy. /// Group send pacing strategy.
///
/// Both modes keep an absolute cadence. If a scheduler delay spans multiple
/// slots, missed historical slots are skipped instead of sent as a catch-up
/// burst.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum ManagedGroupPacing { pub enum ManagedGroupPacing {
/// Send active targets one at a time, spaced approximately interval / N. /// Send active targets one at a time, spaced approximately interval / N.
@@ -362,6 +366,10 @@ fn classify_target_failure(error: &ClientError, opening: bool) -> ManagedTargetF
impl ManagedClientGroup { impl ManagedClientGroup {
/// Start a managed group without creating an initial event subscription. /// Start a managed group without creating an initial event subscription.
///
/// At least one initial target is required to choose the address family for
/// the shared socket. After startup, [`ManagedClientGroupSession::update_targets`]
/// may replace the desired set with an empty set.
pub fn start( pub fn start(
config: ManagedClientGroupConfig, config: ManagedClientGroupConfig,
targets: Vec<ManagedTargetConfig>, targets: Vec<ManagedTargetConfig>,
@@ -370,6 +378,9 @@ impl ManagedClientGroup {
} }
/// Start a managed group and subscribe before worker threads run. /// Start a managed group and subscribe before worker threads run.
///
/// As with [`start`](Self::start), construction requires at least one
/// initial target.
pub fn start_with_subscription( pub fn start_with_subscription(
config: ManagedClientGroupConfig, config: ManagedClientGroupConfig,
targets: Vec<ManagedTargetConfig>, targets: Vec<ManagedTargetConfig>,
@@ -514,6 +525,11 @@ impl ManagedClientGroupSession {
} }
/// Wait for the scheduler and receive threads to finish. /// Wait for the scheduler and receive threads to finish.
///
/// The returned outcome contains aggregate counts plus a bounded recent
/// target-outcome snapshot. Authoritative outcomes are published through
/// [`ManagedGroupEvent::TargetFinished`] before the subscription is sealed,
/// and queued events remain drainable after this method returns.
pub fn join(mut self) -> Result<ManagedGroupOutcome, ClientError> { pub fn join(mut self) -> Result<ManagedGroupOutcome, ClientError> {
let scheduler = self.scheduler.take().expect( let scheduler = self.scheduler.take().expect(
"ManagedClientGroupSession invariant violated: scheduler handle missing before join", "ManagedClientGroupSession invariant violated: scheduler handle missing before join",
+2 -1
View File
@@ -25,7 +25,8 @@ const IDLE_SLEEP: Duration = Duration::from_millis(1);
/// The managed API owns the lower-level [`Client`](crate::Client) loop: it /// The managed API owns the lower-level [`Client`](crate::Client) loop: it
/// opens the session, sends probes at the negotiated interval, receives /// opens the session, sends probes at the negotiated interval, receives
/// datagrams, publishes [`ClientEvent`] values, and closes the session when the /// datagrams, publishes [`ClientEvent`] values, and closes the session when the
/// run completes or is cancelled. /// run completes or is cancelled. Delayed workers skip missed pacing slots
/// instead of sending catch-up bursts.
#[derive(Debug)] #[derive(Debug)]
pub struct ManagedClient; pub struct ManagedClient;