pub struct PostgresRateLimitCounter { /* private fields */ }Expand description
A RateLimitCounter backed by a PostgreSQL table.
Suits a deployment already sharing a PostgreSQL task store: no second
piece of infrastructure, and the counter is as available as the store
the agent already depends on.
It is not the fastest possible shared counter — an in-memory keyspace
like Redis will beat a durable table — and that is the trade being
made. A deployment that needs the last microsecond implements
RateLimitCounter against Redis instead; the trait exists so that is
a few lines rather than a fork.
Implementations§
Source§impl PostgresRateLimitCounter
impl PostgresRateLimitCounter
Sourcepub async fn new(url: &str) -> A2aResult<Self>
pub async fn new(url: &str) -> A2aResult<Self>
Connects to url and creates the counter table if it is absent.
§Durability, deliberately traded away
Sessions on this pool run with synchronous_commit = off, so an
increment is not waiting on a WAL fsync. Measured on loopback, that
is the difference between 598us and 232us per request — the
fsync was almost two thirds of the cost.
It is the right trade for this data specifically, and would not be for most: a rate-limit count describes one window, is superseded when the window rolls, and is swept away shortly after. The worst a crash can do is forget that a caller had used part of its budget in the last moments before it — which lets a few extra requests through, once, on a server that has just restarted.
The setting is scoped to the pool this constructor owns.
from_pool deliberately does not apply it: the
pool handed in there is usually the task store’s, and quietly making
a task store non-durable to speed up a counter would be an
appalling thing to do behind a caller’s back. A caller who wants
both can say so on their own pool.
§Errors
A2aError::internal if the database cannot be reached or the
table cannot be created.
Sourcepub async fn from_pool(pool: PgPool) -> A2aResult<Self>
pub async fn from_pool(pool: PgPool) -> A2aResult<Self>
Uses an existing pool — the usual choice when the deployment already has one for its task store, so the limiter adds no connections.
Unlike new, this leaves the pool’s settings exactly
as the caller configured them, including durability. That costs
roughly 2.8x per request against a pool with
synchronous_commit = off, and it is not this constructor’s call to
make on a pool it does not own.
§Errors
A2aError::internal if the table cannot be created.
Trait Implementations§
Source§impl Debug for PostgresRateLimitCounter
impl Debug for PostgresRateLimitCounter
Auto Trait Implementations§
impl !Freeze for PostgresRateLimitCounter
impl !RefUnwindSafe for PostgresRateLimitCounter
impl !UnwindSafe for PostgresRateLimitCounter
impl Send for PostgresRateLimitCounter
impl Sync for PostgresRateLimitCounter
impl Unpin for PostgresRateLimitCounter
impl UnsafeUnpin for PostgresRateLimitCounter
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
Source§impl<T> FutureExt for T
impl<T> FutureExt for T
Source§fn with_context(self, otel_cx: Context) -> WithContext<Self> ⓘ
fn with_context(self, otel_cx: Context) -> WithContext<Self> ⓘ
Source§fn with_current_context(self) -> WithContext<Self> ⓘ
fn with_current_context(self) -> WithContext<Self> ⓘ
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§impl<T> IntoRequest<T> for T
impl<T> IntoRequest<T> for T
Source§fn into_request(self) -> Request<T>
fn into_request(self) -> Request<T>
T in a tonic::Request