reliakit-timeout
Clock-agnostic deadlines and timeouts for Rust.
reliakit-timeout answers one question: has my time budget run out, and how
much is left? It does not read the clock, sleep, or spawn anything — you
capture a start instant and a budget, then pass now to the query methods. That
keeps it usable from synchronous code, any async runtime, and no_std /
embedded targets, with deterministic tests.
Time is a plain u64 in any monotonic unit you choose (milliseconds is
typical), matching reliakit-circuit and reliakit-ratelimit. All arithmetic
saturates, so no method panics — not on overflow, and not on a clock that moves
backwards.
The crate has no required dependencies, is #![no_std], and forbids unsafe code.
What This Crate Does
Timeout— a reusable budget that is not yet pinned to a timeline. Configure it once, then callTimeout::start(now)per operation to get aDeadline.Deadline— a budget pinned to a start instant; it expires atstart + budget. Query it with:remaining(now)/elapsed(now)— saturating time left / time used.is_expired(now)— whethernow >= expiry.check(now)—Some(remaining)while live,Noneonce expired.allows(now, duration)— whether an operation of that length still fits.clamp(now, duration)—durationcapped to the time left in the budget.
What This Crate Does Not Do
It does not sleep, cancel futures, or enforce the timeout for you. It tracks a
budget against a clock you own; you decide what to do when it expires. Pair it
with your runtime's timer or select! to actually abort work.
Installation
[]
= "0.1"
This crate is no_std with no required dependencies. It has one optional
feature, core (off by default), which pulls in reliakit-core and adds
*_now(clock) convenience methods on Timeout and Deadline backed by its
Clock trait; the existing now: u64 methods are unchanged.
Example
use ;
// A 30s budget (here in milliseconds), pinned to the start of the operation.
let policy = new;
let deadline = policy.start; // started at t = 1_000
assert_eq!;
assert_eq!;
assert_eq!; // expired
Bound a retry delay by the time left in the budget:
use Deadline;
let deadline = new;
let proposed_backoff = 800;
let now = 500;
if !deadline.is_expired
Behavior
| Method | Result |
|---|---|
expiry() |
start + budget (saturating) |
remaining(now) |
expiry - now, saturating to 0 once expired |
elapsed(now) |
now - start, saturating to 0 before start |
is_expired(now) |
now >= expiry (a zero budget expires immediately) |
check(now) |
Some(remaining) while live, else None |
clamp(now, d) |
min(d, remaining(now)) |
Safety
This crate is #![forbid(unsafe_code)] and #![no_std]. Every method is a
const fn over saturating integer arithmetic, so there is no input — including a
backwards clock or an overflowing start + budget — that panics.
Minimum Supported Rust Version
Rust 1.85 and newer. No nightly features are used.
License
Licensed under the MIT License. See LICENSE.