hyperi_rustlib/concurrency/error.rs
1// Project: hyperi-rustlib
2// File: src/concurrency/error.rs
3// Purpose: Error types for the three async concurrency primitives
4// Language: Rust
5//
6// License: BUSL-1.1
7// Copyright: (c) 2026 HYPERI PTY LIMITED
8
9//! Error types for [`crate::concurrency`] primitives.
10//!
11//! Three concrete error enums, one per primitive:
12//! [`SinkError`] for `BackgroundSink`, [`TickError`] for `PeriodicWorker`,
13//! [`ActorError`] for `ActorHandle`. Plus [`DrainError`] for `SinkDrain`
14//! implementations to report backend failures back to the actor.
15
16use std::error::Error as StdError;
17
18use thiserror::Error;
19
20/// Errors returned by [`super::BackgroundSink`] push / flush operations.
21#[derive(Debug, Error)]
22pub enum SinkError {
23 /// Queue full and `Overflow::Drop` was selected -- message discarded
24 /// and the sink's `dropped` counter incremented.
25 #[error("background sink queue full (overflow=drop policy)")]
26 Overflow,
27
28 /// The background actor has exited (shutdown cancelled or all
29 /// senders dropped). No further pushes will succeed.
30 #[error("background sink actor has exited")]
31 Closed,
32
33 /// A drain implementation reported an error during a batch write.
34 /// The actor logs + counts these and continues; this variant is
35 /// only surfaced if the caller asks the sink for a propagated error
36 /// (rare -- drain failures are usually observed via the
37 /// `<prefix>_write_errors_total` metric).
38 #[error("drain failure: {0}")]
39 Drain(#[from] DrainError),
40}
41
42/// Errors returned by [`super::SinkDrain`] implementations.
43///
44/// Drain failures are logged + counted but do NOT terminate the actor.
45/// The actor continues draining subsequent batches. If a drain
46/// consistently fails, operators see rising `<prefix>_write_errors_total`
47/// and the `<prefix>_pending` gauge climbing toward the queue cap.
48#[derive(Debug, Error)]
49pub enum DrainError {
50 /// Standard library I/O error (file writes, syscalls, etc.).
51 #[error("io: {0}")]
52 Io(#[from] std::io::Error),
53
54 /// Backend-specific error wrapped as `Box<dyn Error>`. Backends
55 /// (Kafka, Redis, HTTP) convert their native error types into this
56 /// via `From` impls in their own modules.
57 #[error("backend: {0}")]
58 Backend(Box<dyn StdError + Send + Sync>),
59}
60
61/// Errors returned by [`super::PeriodicTask`] tick implementations.
62///
63/// Tick errors are logged at WARN and do NOT terminate the worker --
64/// the next tick still fires. Consumers wanting fail-fast must return
65/// `Ok(())` from `tick` and surface their failure differently (e.g.
66/// via a `failed: AtomicBool` flag the parent process polls).
67#[derive(Debug, Error)]
68pub enum TickError {
69 /// Generic error wrapper. Most tick implementations only have one
70 /// failure mode and convert their native error type into this.
71 #[error("{0}")]
72 Generic(Box<dyn StdError + Send + Sync>),
73}
74
75/// Errors returned by [`super::ActorHandle`] send operations.
76#[derive(Debug, Error)]
77pub enum ActorError {
78 /// `try_send` saw a full command queue. Caller chooses whether to
79 /// drop, retry, or escalate.
80 #[error("actor command queue full")]
81 Full,
82
83 /// The actor task has exited. No further commands accepted.
84 #[error("actor has exited")]
85 Closed,
86}