Coverage for src / lexigram / contracts / core / idempotency.py: 0%
15 statements
« prev ^ index » next coverage.py v7.13.5, created at 2026-08-15 18:57 +0800
« prev ^ index » next coverage.py v7.13.5, created at 2026-08-15 18:57 +0800
1"""Idempotency store contract."""
3from __future__ import annotations
5from typing import TYPE_CHECKING, Any, Protocol, runtime_checkable
7if TYPE_CHECKING:
8 from lexigram.contracts.core.result import Result
9 from lexigram.contracts.domain.idempotency import IdempotencyRecord
10 from lexigram.contracts.exceptions.idempotency import IdempotencyError
13@runtime_checkable
14class IdempotencyStoreProtocol(Protocol):
15 """Protocol for storing and checking idempotency keys."""
17 async def get(self, key: str) -> Result[Any | None, IdempotencyError]:
18 """Retrieve a stored result by idempotency key.
20 Args:
21 key: The idempotency key.
23 Returns:
24 ``Ok(value)`` when a cached result exists.
25 ``Ok(None)`` when the key is not present or expired.
26 ``Err(IdempotencyError)`` on store failures.
27 """
28 ...
30 async def get_record(
31 self,
32 key: str,
33 ) -> Result[IdempotencyRecord | None, IdempotencyError]:
34 """Retrieve the full idempotency record, including metadata."""
35 ...
37 async def set(
38 self,
39 key: str,
40 value: Any,
41 ttl: float | None = None,
42 ) -> Result[None, IdempotencyError]:
43 """Store a result with an optional time-to-live.
45 Args:
46 key: The idempotency key.
47 value: The result to store.
48 ttl: Time-to-live in seconds, or ``None`` for no expiry.
49 """
50 ...
52 async def delete(self, key: str) -> Result[None, IdempotencyError]:
53 """Remove an idempotency record by key."""
54 ...
56 async def acquire(self, key: str, ttl: int) -> Result[bool, IdempotencyError]:
57 """Atomically claim an idempotency key if it is not already held.
59 Args:
60 key: The idempotency key to acquire.
61 ttl: Time-to-live in seconds for the claimed key.
63 Returns:
64 ``Ok(True)`` if this caller should proceed.
65 ``Ok(False)`` if the key is already claimed.
66 ``Err(IdempotencyError)`` on store failures.
67 """
68 ...
71@runtime_checkable
72class IdempotencyMiddlewareProtocol(Protocol):
73 """Protocol for HTTP idempotency deduplication middleware."""
75 async def process(
76 self,
77 headers: dict[str, str],
78 handler: Any,
79 *args: Any,
80 **kwargs: Any,
81 ) -> Any:
82 """Run the handler with idempotency deduplication."""
83 ...
85 @property
86 def ttl(self) -> float:
87 """Default TTL (seconds) for cached idempotency results."""
88 ...
91__all__ = [
92 "IdempotencyMiddlewareProtocol",
93 "IdempotencyStoreProtocol",
94]