Skip to main content

BudgetedHttpClient

Struct BudgetedHttpClient 

Source
pub struct BudgetedHttpClient { /* private fields */ }
Expand description

Wraps any HttpClient with the outbound budgets of issue #765: a shared token bucket per upstream key, a daily quota with alerts, and Retry-After-aware retries for idempotent calls. Adapters opt in by wrapping the client they already hold — the runtime’s BoundedHttpClient stays the innermost hop, so the port’s own bounds still apply underneath.

The streaming twin (HttpClient::send_streaming) spends the same budget the same way before the head, then hands the body through untouched: the retry loop covers the head only, because a body that has started arriving can never be replayed.

Implementations§

Source§

impl BudgetedHttpClient

Source

pub fn new( inner: Arc<dyn HttpClient>, clock: Arc<dyn Clock>, db: Arc<dyn Database>, router: BudgetRouter, ) -> Self

Budgets inner’s sends through router, reading wall time from clock and spending buckets and quotas against db.

Source

pub fn with_retry(self, policy: RetryPolicy) -> Self

Replaces the retry policy.

Source

pub fn with_events(self, bus: EventBus) -> Self

Emits EVENT_QUOTA_WARNING / EVENT_QUOTA_EXHAUSTED to bus as the daily quotas are crossed.

Source

pub fn with_defer(self, defer: Arc<dyn Defer>) -> Self

Runs the alert events’ handlers through this defer. Without it the default NoopDefer drops them (with a warning), so a deployment that subscribes to the quota events mounts the port’s defer here.

Source

pub fn with_sleeper(self, sleeper: Sleeper) -> Self

Replaces the sleep pacing and backoff wait through — the hook a runtime with a native timer (or a test that asserts on delays) supplies.

Source

pub fn with_bucket_table(self, table: impl Into<String>) -> Self

Renames the pacing-bucket table.

Source

pub fn with_quota_table(self, table: impl Into<String>) -> Self

Renames the daily-quota table.

Source

pub fn with_alert_table(self, table: impl Into<String>) -> Self

Renames the quota-alert claim table.

Source

pub fn create_bucket_table_sql(table: &str) -> String

The portable DDL for the pacing-bucket table. The daily-quota table is Usage::create_table_sql and the quota-alert claim table is create_alert_table_sql — a venture budgets only when it has created all three.

Source

pub fn create_alert_table_sql(table: &str) -> String

The portable DDL for the quota-alert claim table: one row per (subject, day, kind) emission already made, the at-most-once gate behind EVENT_QUOTA_WARNING / EVENT_QUOTA_EXHAUSTED. The claim’s subject column names the quota table too, so two clients metering different tables never claim each other’s alerts. A venture that wires with_events ships this as a migration beside the other two; a claim that meets its absence creates it on demand (the same DDL, IF NOT EXISTS) rather than dropping the alert.

Trait Implementations§

Source§

impl HttpClient for BudgetedHttpClient

Source§

fn send<'life0, 'async_trait>( &'life0 self, request: Request<Bytes>, ) -> Pin<Box<dyn Future<Output = Result<Response<Bytes>, HttpError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Sends request and returns the fully-buffered response under the bounds this port carries: the body is at most MAX_RESPONSE_BYTES unless an HttpPolicy tightens it, the exchange is bounded by that policy’s deadline (enforced through BoundedHttpClient on runtimes that wrap), the destination is vetted where real sockets are opened, and a runtime that keeps a concurrency budget holds one for the send. Read more
Source§

fn send_streaming<'life0, 'async_trait>( &'life0 self, request: Request<Bytes>, ) -> Pin<Box<dyn Future<Output = Result<Response<ByteStream>, HttpError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Sends request and returns the response with its body as a stream (issue #859): the status and headers are known when the future resolves — the head is bounded by HttpPolicy::timeout, the same deadline send answers under — and the bytes arrive chunk by chunk afterwards, under the StreamPolicy the request carries. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self> ⓘ

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self> ⓘ

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self> ⓘ
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self> ⓘ

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more