///|
/// Admission control for logical request buckets. Every completed acquire
/// has one release with that acquire's Admission, including cancellation and
/// decoding failures. Implementations ignore repeated releases of a token.
pub(open) trait RateLimiter {
async fn acquire(Self, String, global_exempt~ : Bool) -> Admission
async fn release(Self, Admission, status~ : Int32, headers~ : @http.Headers) -> Unit
}
///|
/// An admission issued by a RateLimiter. Return it only to its issuing limiter.
/// Copies identify the same admission; a second release is ignored.
pub struct Admission {
priv bucket : String
priv sequence : Int64
}
///|
/// Creates a token for a custom limiter. The issuer assigns a strictly
/// increasing sequence and tracks outstanding tokens to ignore duplicate releases.
pub fn Admission::new(bucket : String, sequence~ : Int64) -> Admission {
{ bucket, sequence, }
}
///|
/// The logical request bucket passed to acquire.
pub fn Admission::bucket(self : Admission) -> String {
self.bucket
}
///|
/// The issuer's admission sequence, independent of response delivery time.
pub fn Admission::sequence(self : Admission) -> Int64 {
self.sequence
}
///|
/// Admission without throttling or retained state.
pub struct NoLimiter {
priv mut sequence : Int64
}
///|
/// Creates an admission controller that admits immediately.
pub fn NoLimiter::new() -> NoLimiter {
{ sequence: 0L, }
}
///|
/// Calls admission and release through method syntax.
pub extend NoLimiter with RateLimiter::{acquire, release}
///|
/// Admits immediately.
pub impl RateLimiter for NoLimiter with fn acquire(self, bucket, global_exempt~) {
let _ = global_exempt
if self.sequence == 9223372036854775807L {
raise @http.TransportError(
kind=Invalid,
phase=Pool,
detail="admission sequence exhausted",
)
}
self.sequence += 1L
Admission::new(bucket, sequence=self.sequence)
}
///|
/// Releases without retaining telemetry.
pub impl RateLimiter for NoLimiter with fn release(_, _, status~, headers~) {
let _ = (status, headers)
}
///|
/// A settled attempt, reported after releasing admission. Attempt zero is
/// the initial send; status zero means no response head arrived.
pub(all) struct Attempt {
request : @http.RequestHead
/// Explicit caller annotations for observations, separate from the pure head.
attributes : @http.Attributes
bucket : String
attempt : Int32
status : Int32
headers : @http.Headers
duration_ms : Int64
error : Error?
decision : @retry.Decision?
}