pub struct Budget {
pub deadline: Option<Time>,
pub poll_quota: u32,
pub cost_quota: Option<u64>,
pub priority: u8,
}Expand description
A budget constraining resource usage for a task or region.
Budgets form a product semiring for combination:
- Deadlines/quotas use min (tighter wins)
- Priority uses max (higher urgency wins)
§Choosing a deadline constructor
Absolute vs. relative time is the classic budget footgun. Pick from this
table; the at / timeout words in the names mark the semantics:
| You have | You want | Use |
|---|---|---|
An absolute logical instant (Time) | deadline at that instant | with_deadline |
| An absolute instant in raw seconds/nanos | deadline at that instant | with_deadline_at_secs / with_deadline_at_ns |
now + a relative timeout | deadline replaced by now + timeout | with_timeout |
now + a relative timeout | deadline tightened, never loosened | tightened_by_timeout |
A Cx + a relative timeout | ambient budget tightened correctly | Cx::budget_for_timeout |
For deadline propagation across calls (HTTP → handler → DB), always use the tightening forms — replacing a deadline can silently extend it past the caller’s bound.
Fields§
§deadline: Option<Time>Absolute deadline by which work must complete.
poll_quota: u32Maximum number of poll operations.
cost_quota: Option<u64>Abstract cost quota (for advanced scheduling).
priority: u8Scheduling priority (0 = lowest, 255 = highest).
Implementations§
Source§impl Budget
impl Budget
Sourcepub const MINIMAL: Self
pub const MINIMAL: Self
A minimal budget for cleanup operations.
This provides a small poll quota (100 polls) for cleanup and finalizer code to run, but no deadline or cost constraints. Used when requesting cancellation to allow tasks a bounded cleanup phase.
Sourcepub const fn new() -> Self
pub const fn new() -> Self
Creates a new budget with default values (priority 128, unlimited quotas).
Sourcepub const fn with_deadline_at_secs(secs: u64) -> Self
pub const fn with_deadline_at_secs(secs: u64) -> Self
Creates a budget with only an absolute deadline constraint (in seconds).
The at in the name is deliberate: the value is a logical instant
since the runtime epoch (“deadline AT t=30s”), not a timeout duration.
For a per-operation timeout, use with_timeout
or tightened_by_timeout with the
current logical time.
§Example
let budget = Budget::with_deadline_at_secs(30);
assert_eq!(budget.deadline, Some(Time::from_secs(30)));Sourcepub const fn with_deadline_at_ns(nanos: u64) -> Self
pub const fn with_deadline_at_ns(nanos: u64) -> Self
Creates a budget with only an absolute deadline constraint (in nanoseconds).
The at in the name is deliberate: the value is a logical instant
since the runtime epoch, not a timeout duration. For a per-operation
timeout, use with_timeout or
tightened_by_timeout with the current
logical time.
§Example
let budget = Budget::with_deadline_at_ns(30_000_000_000); // 30 seconds
assert_eq!(budget.deadline, Some(Time::from_nanos(30_000_000_000)));Sourcepub const fn with_deadline(self, deadline: Time) -> Self
pub const fn with_deadline(self, deadline: Time) -> Self
Sets the absolute logical deadline.
The deadline is an instant, not a duration. For example,
Time::from_secs(30) means the runtime/lab clock value 30s, not
“30 seconds from now”. For relative per-operation timeouts, use
with_timeout.
Sourcepub fn with_timeout(self, now: Time, timeout: Duration) -> Self
pub fn with_timeout(self, now: Time, timeout: Duration) -> Self
Sets the deadline to now + timeout.
Use this for request, RPC, database, and other per-operation timeout
budgets. The caller supplies now explicitly so production and lab
runtimes use the same deterministic time source.
§Example
let now = Time::from_secs(100);
let budget = Budget::new().with_timeout(now, Duration::from_secs(30));
assert_eq!(budget.deadline, Some(Time::from_secs(130)));Sourcepub fn tightened_by_timeout(self, now: Time, timeout: Duration) -> Self
pub fn tightened_by_timeout(self, now: Time, timeout: Duration) -> Self
Tightens this budget with a relative timeout, never loosening it.
Unlike with_timeout, which replaces any
existing deadline, this composes via meet: the
resulting deadline is min(existing_deadline, now + timeout). This is
the correct operation for deadline propagation — an outer 10s request
budget tightened by a 30s per-call timeout stays a 10s budget.
All other dimensions (poll quota, cost quota, priority) are preserved.
§Example
let now = Time::from_secs(100);
// Ambient deadline at t=110s; a 30s timeout must NOT loosen it.
let ambient = Budget::new().with_deadline(Time::from_secs(110));
let tightened = ambient.tightened_by_timeout(now, Duration::from_secs(30));
assert_eq!(tightened.deadline, Some(Time::from_secs(110)));
// No ambient deadline: the timeout becomes the deadline.
let open = Budget::new();
let bounded = open.tightened_by_timeout(now, Duration::from_secs(30));
assert_eq!(bounded.deadline, Some(Time::from_secs(130)));Sourcepub const fn with_poll_quota(self, quota: u32) -> Self
pub const fn with_poll_quota(self, quota: u32) -> Self
Sets the poll quota.
Sourcepub const fn with_cost_quota(self, quota: u64) -> Self
pub const fn with_cost_quota(self, quota: u64) -> Self
Sets the cost quota.
Sourcepub const fn with_priority(self, priority: u8) -> Self
pub const fn with_priority(self, priority: u8) -> Self
Sets the priority.
Sourcepub const fn is_exhausted(&self) -> bool
pub const fn is_exhausted(&self) -> bool
Returns true if the budget has been exhausted.
This checks only poll and cost quotas, not deadline (which requires current time).
Sourcepub fn is_past_deadline(&self, now: Time) -> bool
pub fn is_past_deadline(&self, now: Time) -> bool
Returns true if the deadline has passed.
Sourcepub fn consume_poll(&mut self) -> Option<u32>
pub fn consume_poll(&mut self) -> Option<u32>
Decrements the poll quota by one, returning the old value.
Returns None if already at zero.
Sourcepub fn combine(self, other: Self) -> Self
pub fn combine(self, other: Self) -> Self
Combines two budgets using product semiring semantics.
- Deadlines: min (earlier wins)
- Quotas: min (tighter wins)
- Priority: max (higher urgency wins)
This is also known as the “meet” operation (∧) in lattice terminology.
See also: meet.
§Example
let outer = Budget::new()
.with_deadline(Time::from_secs(30))
.with_poll_quota(1000);
let inner = Budget::new()
.with_deadline(Time::from_secs(10)) // tighter
.with_poll_quota(5000); // looser
let combined = outer.combine(inner);
assert_eq!(combined.deadline, Some(Time::from_secs(10))); // min
assert_eq!(combined.poll_quota, 1000); // minSourcepub fn meet(self, other: Self) -> Self
pub fn meet(self, other: Self) -> Self
Meet operation (∧) - alias for combine.
Computes the tightest constraints from two budgets. This is the fundamental operation for nesting budget scopes.
§Example
let parent = Budget::with_deadline_at_secs(30);
let child = Budget::with_deadline_at_secs(10);
// Child deadline is tighter, so it wins
let effective = parent.meet(child);
assert_eq!(effective.deadline, Some(Time::from_secs(10)));Sourcepub fn consume_cost(&mut self, cost: u64) -> bool
pub fn consume_cost(&mut self, cost: u64) -> bool
Consumes cost quota, returning true if successful.
Returns false (and does not modify quota) if there isn’t enough
remaining cost quota. If no cost quota is set, always succeeds.
§Example
let mut budget = Budget::new().with_cost_quota(100);
assert!(budget.consume_cost(30)); // 70 remaining
assert!(budget.consume_cost(70)); // 0 remaining
assert!(!budget.consume_cost(1)); // fails, quota exhaustedSourcepub fn remaining_time(&self, now: Time) -> Option<Duration>
pub fn remaining_time(&self, now: Time) -> Option<Duration>
Returns the remaining time until the deadline, if any.
Returns None if there is no deadline or if the deadline has passed.
§Example
let budget = Budget::with_deadline_at_secs(30);
let now = Time::from_secs(10);
let remaining = budget.remaining_time(now);
assert_eq!(remaining, Some(Duration::from_secs(20)));Sourcepub const fn remaining_polls(&self) -> u32
pub const fn remaining_polls(&self) -> u32
Returns the remaining poll quota.
Returns the current poll quota value. A value of u32::MAX indicates
effectively unlimited polls.
§Example
let budget = Budget::new().with_poll_quota(100);
assert_eq!(budget.remaining_polls(), 100);Sourcepub const fn remaining_cost(&self) -> Option<u64>
pub const fn remaining_cost(&self) -> Option<u64>
Returns the remaining cost quota, if any.
Returns None if no cost quota is set (unlimited).
§Example
let budget = Budget::new().with_cost_quota(1000);
assert_eq!(budget.remaining_cost(), Some(1000));
let unlimited = Budget::unlimited();
assert_eq!(unlimited.remaining_cost(), None);Sourcepub fn remaining(&self, now: Time) -> RemainingBudget
pub fn remaining(&self, now: Time) -> RemainingBudget
Returns a point-in-time snapshot of every remaining budget dimension.
This aggregates remaining_time,
remaining_polls, and
remaining_cost into one structure, mapping
“effectively unlimited” sentinel values to None so callers can write
if let Some(left) = snapshot.polls without knowing the sentinels.
The snapshot is valid at the moment of the call only; quotas continue to drain as the task runs.
§Example
let now = Time::from_secs(10);
let budget = Budget::new()
.with_deadline(Time::from_secs(30))
.with_poll_quota(100);
let left = budget.remaining(now);
assert_eq!(left.deadline, Some(Duration::from_secs(20)));
assert_eq!(left.polls, Some(100));
assert_eq!(left.cost, None); // no cost quota configuredSourcepub fn to_timeout(&self, now: Time) -> Option<Duration>
pub fn to_timeout(&self, now: Time) -> Option<Duration>
Converts the deadline to a timeout duration from the given time.
Returns the same value as remaining_time.
This method is provided for API compatibility with timeout-based systems.
§Example
let budget = Budget::with_deadline_at_secs(30);
let now = Time::from_secs(5);
// 25 seconds remaining
let timeout = budget.to_timeout(now);
assert_eq!(timeout, Some(Duration::from_secs(25)));Trait Implementations§
Source§impl BudgetTimeExt for Budget
impl BudgetTimeExt for Budget
impl Copy for Budget
impl Eq for Budget
Source§impl From<Budget> for BudgetSnapshot
impl From<Budget> for BudgetSnapshot
Source§impl LocalToDistributed for Budget
impl LocalToDistributed for Budget
Source§type Distributed = BudgetSnapshot
type Distributed = BudgetSnapshot
Source§fn to_distributed(&self) -> BudgetSnapshot
fn to_distributed(&self) -> BudgetSnapshot
impl StructuralPartialEq for Budget
Auto Trait Implementations§
impl Freeze for Budget
impl RefUnwindSafe for Budget
impl Send for Budget
impl Sync for Budget
impl Unpin for Budget
impl UnsafeUnpin for Budget
impl UnwindSafe for Budget
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
key and return true if they are equal.