pub struct SpooledClient { /* private fields */ }Expand description
A durable-emit wrapper around a crate::Client.
Holds the client, the spool path, and an in-process Mutex that serializes
every spool-file operation (single-producer-per-spool-file).
Implementations§
Source§impl SpooledClient
impl SpooledClient
Sourcepub fn new(client: Client, spool_path: PathBuf) -> SpooledClient
pub fn new(client: Client, spool_path: PathBuf) -> SpooledClient
Build an unbounded durable-emit client over client, buffering to
spool_path. Use with_config to opt into a
retention cap.
Sourcepub fn with_config(client: Client, config: SpoolConfig) -> SpooledClient
pub fn with_config(client: Client, config: SpoolConfig) -> SpooledClient
Build from a SpoolConfig, carrying its retention caps.
Sourcepub fn client(&self) -> &Client
pub fn client(&self) -> &Client
Borrow the underlying client for reads / non-spooled ops (retrieve,
health, pin, capsules, …). Only append_observation is durability-wrapped.
Sourcepub async fn append_observation(
&self,
input: ObservationInput,
capsule_id: Option<String>,
validate: Option<bool>,
) -> Result<AppendOutcome, SpoolError>
pub async fn append_observation( &self, input: ObservationInput, capsule_id: Option<String>, validate: Option<bool>, ) -> Result<AppendOutcome, SpoolError>
Append an observation durably.
Assigns a stable v4 id when input.id is None (so a spooled entry and
any replay share one id — see the crate-level Delivery semantics).
Then:
- If the spool already has buffered entries, opportunistically
flushthem first so the daemon observes them in append order ahead of this new one. - Try the daemon. On success →
AppendOutcome::Delivered. - On a connectivity failure (
Unavailable/Http) → buffer to the spool and returnAppendOutcome::Spooled(never an error). - On any other client error → propagate as
SpoolError::Client; the observation is not spooled.
Sourcepub async fn flush(&self) -> Result<FlushReport, SpoolError>
pub async fn flush(&self) -> Result<FlushReport, SpoolError>
Drain the spool into the daemon, in order.
Replays each buffered entry via the client. Stops at the first
connectivity failure (Unavailable / Http), keeping that entry and
the remainder. A non-connectivity client error also stops the drain and
is propagated, but the un-replayed remainder (including the rejected
entry) is preserved — data is never silently dropped.
The spool file is rewritten with exactly the un-replayed remainder via a temp-file-then-rename, so a crash mid-flush cannot corrupt the spool.
If a retention cap is configured (see SpoolConfig), the retained
remainder is trimmed (oldest first) before the rewrite — see the
crate-level Retention docs. This is the only place trimming happens, so
it can never race a concurrent drain.
Sourcepub fn pending_count(&self) -> Result<usize, SpoolError>
pub fn pending_count(&self) -> Result<usize, SpoolError>
Count of pending (un-replayed) spool entries.
Sourcepub async fn spool_status(&self) -> Result<SpoolStatus, SpoolError>
pub async fn spool_status(&self) -> Result<SpoolStatus, SpoolError>
Observability snapshot for this client (pending count + live counters).
Sourcepub fn spool_status_from_path(
spool_path: impl Into<PathBuf>,
) -> Result<SpoolStatus, SpoolError>
pub fn spool_status_from_path( spool_path: impl Into<PathBuf>, ) -> Result<SpoolStatus, SpoolError>
Passive status from an on-disk spool file and its optional .status.json
sidecar (best-effort: a corrupt sidecar is ignored).