Skip to main content

budget_context/
error.rs

1use std::sync::Arc;
2
3use crate::{BudgetId, Resource};
4
5/// Error returned when constructing a resource.
6#[derive(Clone, Debug, Eq, PartialEq, thiserror::Error)]
7#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
8pub enum ResourceError {
9    /// Resource names must contain at least one byte.
10    #[error("resource name cannot be empty")]
11    EmptyName,
12}
13
14/// Error returned when building a budget node.
15#[derive(Clone, Debug, Eq, PartialEq, thiserror::Error)]
16#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
17pub enum BudgetBuildError {
18    /// A resource limit was configured more than once on the same node.
19    #[error("duplicate limit for resource {resource}")]
20    DuplicateLimit {
21        /// The duplicated resource.
22        resource: Resource,
23    },
24
25    /// A relative deadline could not be represented by the platform clock.
26    #[error("deadline is outside the representable clock range")]
27    DeadlineOverflow,
28
29    /// More than one deadline was configured on the builder.
30    #[error("deadline configured more than once")]
31    DuplicateDeadline,
32
33    /// The process-local budget identifier space was exhausted.
34    #[error("process-local budget identifier space exhausted")]
35    BudgetIdExhausted,
36}
37
38/// Error returned by accounting and execution operations.
39#[derive(Clone, Debug, Eq, PartialEq, thiserror::Error)]
40#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
41pub enum BudgetError {
42    /// A limit in the budget lineage rejected an operation.
43    #[error(
44        "resource {resource} exhausted at budget {scope}: requested {requested}, remaining {remaining}"
45    )]
46    Exhausted {
47        /// The exhausted resource.
48        resource: Resource,
49        /// The amount requested by the operation.
50        requested: u64,
51        /// Capacity remaining at the limiting node.
52        remaining: u64,
53        /// Identifier of the first limiting node in root-to-leaf order.
54        scope: BudgetId,
55        /// Optional name of the limiting node.
56        scope_name: Option<Arc<str>>,
57    },
58
59    /// A reservation was reconciled with more usage than it held.
60    ///
61    /// The full reservation is retained as consumed. `unaccounted` reports
62    /// usage which could not be admitted without violating a budget limit.
63    #[error("resource {resource} used {actual}, exceeding reservation {reserved} by {unaccounted}")]
64    ReservationExceeded {
65        /// The resource whose actual usage exceeded its reservation.
66        resource: Resource,
67        /// Reserved capacity converted to consumed capacity.
68        reserved: u64,
69        /// Actual usage reported by the caller.
70        actual: u64,
71        /// Actual usage beyond the reservation.
72        unaccounted: u64,
73    },
74
75    /// Actual usage named a resource absent from the reservation set.
76    ///
77    /// To fail closed, all reservations in the set are converted to consumed
78    /// capacity before this error is returned.
79    #[error("resource {resource} was not part of the reservation set")]
80    UnknownReservationResource {
81        /// The unexpected resource.
82        resource: Resource,
83    },
84
85    /// Checked resource arithmetic overflowed.
86    #[error("resource arithmetic overflow for {resource}")]
87    Overflow {
88        /// The overflowing resource.
89        resource: Resource,
90    },
91
92    /// The effective budget deadline elapsed before an operation began.
93    #[error("budget deadline exceeded")]
94    DeadlineExceeded,
95
96    /// The budget was cancelled.
97    #[cfg(feature = "tokio")]
98    #[error("budget cancelled")]
99    Cancelled,
100}