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}