pub trait IdempotencyStore:
Send
+ Sync
+ 'static {
// Required methods
fn reserve_or_fetch<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
principal: &'life1 str,
key: &'life2 str,
request_hash: [u8; 32],
expires_at: SystemTime,
) -> Pin<Box<dyn Future<Output = Result<ReservationOutcome, CoolError>> + Send + 'async_trait>>
where 'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Self: 'async_trait;
fn complete<'life0, 'life1, 'life2, 'life3, 'life4, 'async_trait>(
&'life0 self,
principal: &'life1 str,
key: &'life2 str,
token: Uuid,
status: u16,
headers: &'life3 [u8],
body: &'life4 [u8],
) -> Pin<Box<dyn Future<Output = Result<(), CoolError>> + Send + 'async_trait>>
where 'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
'life4: 'async_trait,
Self: 'async_trait;
fn release<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
principal: &'life1 str,
key: &'life2 str,
token: Uuid,
) -> Pin<Box<dyn Future<Output = Result<(), CoolError>> + Send + 'async_trait>>
where 'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Self: 'async_trait;
}Required Methods§
Sourcefn reserve_or_fetch<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
principal: &'life1 str,
key: &'life2 str,
request_hash: [u8; 32],
expires_at: SystemTime,
) -> Pin<Box<dyn Future<Output = Result<ReservationOutcome, CoolError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Self: 'async_trait,
fn reserve_or_fetch<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
principal: &'life1 str,
key: &'life2 str,
request_hash: [u8; 32],
expires_at: SystemTime,
) -> Pin<Box<dyn Future<Output = Result<ReservationOutcome, CoolError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Self: 'async_trait,
Atomically reserve (principal, key) for the caller, or report
the outcome of an existing reservation. Implementations MUST be
concurrent-safe: two simultaneous callers seeing the same key and
hash must observe exactly one Reserved and one InFlight,
never two Reserved. The expires_at argument bounds the
reservation’s lifetime so a forgotten release doesn’t pin the
key forever; when a retry reclaims an expired row the store
MUST rotate the reservation token so complete/release from
the original handler can no longer touch the newer slot.
Sourcefn complete<'life0, 'life1, 'life2, 'life3, 'life4, 'async_trait>(
&'life0 self,
principal: &'life1 str,
key: &'life2 str,
token: Uuid,
status: u16,
headers: &'life3 [u8],
body: &'life4 [u8],
) -> Pin<Box<dyn Future<Output = Result<(), CoolError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
'life4: 'async_trait,
Self: 'async_trait,
fn complete<'life0, 'life1, 'life2, 'life3, 'life4, 'async_trait>(
&'life0 self,
principal: &'life1 str,
key: &'life2 str,
token: Uuid,
status: u16,
headers: &'life3 [u8],
body: &'life4 [u8],
) -> Pin<Box<dyn Future<Output = Result<(), CoolError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
'life4: 'async_trait,
Self: 'async_trait,
Persist the captured response for a previously-reserved key so
subsequent attempts replay it. Banks treat the IETF idempotency
contract as “freeze the outcome”: if the handler returned 5xx,
retries see the same 5xx unless they use a fresh key. The
token must match the value returned by reserve_or_fetch
when this caller claimed the key; mismatched tokens are
silently no-ops so a stale handler whose reservation has been
reclaimed cannot overwrite a newer execution’s response.
headers is the encoded blob from super::encode_headers —
replays rebuild the response with the same Location, ETag,
Cache-Control, Content-Type, etc. that the original handler
set.
Sourcefn release<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
principal: &'life1 str,
key: &'life2 str,
token: Uuid,
) -> Pin<Box<dyn Future<Output = Result<(), CoolError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Self: 'async_trait,
fn release<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
principal: &'life1 str,
key: &'life2 str,
token: Uuid,
) -> Pin<Box<dyn Future<Output = Result<(), CoolError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Self: 'async_trait,
Release a reservation without recording a completion (e.g. the
inner service panicked or the middleware itself errored before
the response was ready). Subsequent attempts with the same key
can re-reserve. As with complete, the token must match the
active reservation.