gglib_core/ports/retry_observer.rs
1//! Outbound port for reporting retry activity.
2
3use std::time::Duration;
4
5/// A sink for retry activity on a request that is being re-attempted.
6///
7/// The reporting site — the LLM completion adapter's retry loop — records that
8/// it is backing off without knowing where the notice lands. The agent HTTP
9/// handler implements it by pushing an
10/// [`AgentEvent::SystemWarning`](crate::domain::agent::AgentEvent::SystemWarning)
11/// into the SSE stream it already owns, so a waiting user sees "retrying"
12/// rather than a frozen cursor; a one-shot CLI path with nothing to notify
13/// passes no observer at all, making the calls no-ops.
14///
15/// This mirrors [`CacheMetricsSink`](crate::ports::CacheMetricsSink) — the same
16/// optional-upward-reporting seam, so both are wired into the adapter the same
17/// way and neither couples it to a transport.
18///
19/// Implementations are called from inside the request path and must not block:
20/// a slow observer delays the retry it is describing.
21pub trait RetryObserver: Send + Sync {
22 /// A retry has been scheduled. `attempt` counts completed attempts, so it
23 /// is `1` on the first retry. `delay` is how long the caller is about to
24 /// wait, and `reason` describes the failure being retried.
25 fn on_retry(&self, attempt: u32, delay: Duration, reason: &str);
26
27 /// The sequence gave up. `reason` describes which limit was reached — see
28 /// [`GiveUpReason::as_str`](crate::retry::GiveUpReason::as_str).
29 fn on_exhausted(&self, attempts: u32, elapsed: Duration, reason: &str);
30}