Idempotency
- Start here: Idempotency guide
- Common recipes:
Idempotency,@idempotent - Configuration: Storage, Configuration
grelmicro.idempotency
Idempotency.
Stripe-style idempotency keys for safe retries.
Idempotency("name", ttl=...) stores a response under a caller-supplied
key. A repeated key within ttl replays the stored response without
running the operation again. Use the explicit block form for the most
control, or the @idempotent decorator for a function-level shortcut.
Storage rides the cache layer. Pass an explicit cache= or leave it
unset to resolve the active app's Cache component backend.
Idempotency
Idempotency(
name: str,
*,
ttl: float | None = None,
fingerprint: str | None = None,
cache: TTLCache[T] | None = None,
serializer: CacheSerializer[T] | None = None,
env_prefix: str | None = None,
env_load: bool | None = None,
)
Bases: Reconfigurable[IdempotencyConfig], Generic[T]
Idempotency keys for safe retries of an operation.
Each named Idempotency stores a response under a caller-supplied
key for ttl seconds. A repeated key within that window replays the
stored response without running the operation again. A duplicate
arriving while the first execution is in flight waits and receives
the stored response, across replicas when a lock backend is
configured and in-process otherwise. An exception in the block
stores nothing and a later retry with the same key executes fresh.
Storage rides the cache layer. Pass an explicit cache to bind a
TTLCache, or leave it unset to resolve the active app's Cache
component. Without either, OutOfContextError is raised on first
use.
Supports live reconfiguration via reconfigure(new_config). A swap
takes effect on the next call. In-flight calls keep the config they
started with.
The type parameter T represents the stored response type. Defaults
to Any when unspecified.
Initialize the idempotency namespace.
| PARAMETER | DESCRIPTION |
|---|---|
name
|
The idempotency namespace. Keys are scoped under this name, so the same key used by
two different
TYPE:
|
ttl
|
Lifetime in seconds of a stored response. Default: 86400. When unset and env reads are enabled (see
TYPE:
|
fingerprint
|
Default payload fingerprint applied to every call. A per-call
TYPE:
|
cache
|
The By default, a
TYPE:
|
serializer
|
Serialization strategy for stored responses. Ignored when an explicit
TYPE:
|
env_prefix
|
Override the auto-derived environment variable prefix. Default:
TYPE:
|
env_load
|
Whether to read environment variables. When None (the default), follow the process-wide
TYPE:
|
name
property
name: str
Return the idempotency namespace.
from_config
classmethod
from_config(
name: str,
config: IdempotencyConfig,
*,
fingerprint: str | None = None,
cache: TTLCache[T] | None = None,
serializer: CacheSerializer[T] | None = None,
) -> Self
Construct an Idempotency from a name and a pre-built config.
| PARAMETER | DESCRIPTION |
|---|---|
name
|
The idempotency namespace. Acts as the instance identity.
TYPE:
|
config
|
The pre-built idempotency configuration. Use this path when the configuration is assembled at startup from a settings tree. The environment path is bypassed and the config is used as-is.
TYPE:
|
fingerprint
|
Default payload fingerprint applied to every call.
TYPE:
|
cache
|
The
TYPE:
|
serializer
|
Serialization strategy for stored responses.
TYPE:
|
run
async
run(
key: str,
factory: Callable[[], T] | Callable[[], Awaitable[T]],
*,
fingerprint: str | None = None,
) -> T
Run an operation once for key, then replay its response.
On a first execution the factory runs, its result is stored,
and the result is returned. A later call with the same key within
ttl replays the stored response without running the factory
again. A failing factory stores nothing, so a later retry runs
fresh.
| PARAMETER | DESCRIPTION |
|---|---|
key
|
The idempotency key derived from the request.
TYPE:
|
factory
|
Sync or async callable that produces the response on a first execution. Awaited when it returns a coroutine.
TYPE:
|
fingerprint
|
Payload fingerprint for this call. Overrides the instance-level
TYPE:
|
IdempotencyConfig
Bases: BaseModel
Frozen snapshot of the Idempotency declarative settings.
Carries the settings that round-trip in serialized form. Runtime
dependencies (cache, serializer, fingerprint) stay as
constructor kwargs on Idempotency since they are object references
or callables, not values.
ttl
class-attribute
instance-attribute
ttl: PositiveFloat = 86400
Lifetime in seconds of a stored response. A repeated key within this window replays the stored response. After it elapses, the key executes fresh.
IdempotencyConflictError
IdempotencyConflictError(*, name: str, key: str)
Bases: IdempotencyError
Raised when a key is replayed with a different payload fingerprint.
The same idempotency key arrived twice with different payloads. The stored fingerprint from the first execution does not match the fingerprint supplied on the replay, so the second call is rejected instead of returning a response computed for a different request.
Initialize the error.
name
instance-attribute
name = name
key
instance-attribute
key = key
IdempotencyError
Bases: GrelmicroError
Base idempotency error.
Operation
Operation(*, replayed: bool, response: T | None)
Bases: Generic[T]
Handle for a single idempotent operation, yielded by Idempotency.__call__.
On a replay, replayed is True and response carries the stored
value. On a first execution, replayed is False and the body runs
the work and calls store(response) to persist it.
Initialize the operation handle.
replayed
property
replayed: bool
Whether the key was already stored and the response replayed.
response
property
response: T | None
The stored response when replayed is True, else None.
store
store(response: T) -> None
Record the response to persist for this key.
Called once during a first execution. The value is written when the block exits without an exception. Calling it on a replay is a no-op.
| PARAMETER | DESCRIPTION |
|---|---|
response
|
The response to store and replay on later calls.
TYPE:
|
idempotent
idempotent(
idempotency: Idempotency[Any],
*,
key: Callable[..., str],
fingerprint: Callable[..., str] | None = None,
) -> Callable[[Callable[P, R]], Callable[P, R]]
Make an async function idempotent on a per-call key.
On a first call for a key, the function runs and its return value is
stored. A later call with the same key within the configured ttl
replays the stored value without running the function again. A
failing call stores nothing, so a later retry executes fresh.
The decorated function must be a coroutine function.
| PARAMETER | DESCRIPTION |
|---|---|
idempotency
|
The
TYPE:
|
key
|
Derive the idempotency key from the call arguments. Receives the same positional and keyword arguments as the decorated function and returns the key string.
TYPE:
|
fingerprint
|
Optional payload fingerprint derived from the call arguments.
Receives the same arguments as the decorated function. A
replay with a different fingerprint raises
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
Callable[[Callable[P, R]], Callable[P, R]]
|
A decorator that makes the function idempotent. |