Production-ready idempotency library for async Python applications
Project description
idempotency-kit
Production-ready idempotency library for async Python applications.
Ensure operations execute exactly once, even when called multiple times with the same idempotency key. Built for production microservices with graceful degradation, collision handling, and observability.
Features
- Clean Architecture — core domain separated from infrastructure
- Protocol-Based — easy to swap storage backends (Redis, custom)
- Type-Safe — full type hints with Pydantic validation
- Async First — built for asyncio applications
- Graceful Degradation — high availability over strict exactly-once
- Collision Handling — automatic resolution of concurrent requests
- Observability — built-in metrics (hits, misses, collisions, latency)
- Bulk Operations — efficient
get_many,save_many,delete_many - Redis Cluster Compatible — non-transactional pipelines
- Decorator Pattern —
@async_idempotentfor zero-boilerplate integration
Installation
pip install idempotency-kit
# With Redis support (recommended)
pip install idempotency-kit[redis]
# With Dishka DI
pip install idempotency-kit[dishka,redis]
Requirements: Python 3.11+, Redis 6+
Quick start
from idempotency_kit import AsyncIdempotencyCoordinator, PydanticResultAdapter, async_idempotent
class CreateOrderUseCase:
def __init__(self, uow: AsyncUnitOfWork, coordinator: AsyncIdempotencyCoordinator):
self._uow = uow
self.coordinator = coordinator
@async_idempotent(
operation="order.create",
adapter=PydanticResultAdapter(OrderDTO),
)
async def execute(
self,
dto: CreateOrderDTO,
idempotency_key: str | None = None,
) -> OrderDTO:
"""Create order - idempotency handled automatically."""
async with self._uow.transaction() as tx:
# Your business logic - no idempotency code needed!
order = await tx.orders.create(dto.items, dto.total)
await tx.outbox.create(OrderCreatedEvent(order_id=order.id))
return OrderDTO.from_entity(order)
Pass idempotency_key to downstream services for distributed idempotency:
# Orchestrate multiple services with same key
await identity_service.create_user(..., idempotency_key=idempotency_key)
await payment_service.charge(..., idempotency_key=idempotency_key)
How it works
1. Client provides key
POST /api/orders
Idempotency-Key: abc-123-def
2. Server checks cache
cached = await repo.get("order.create", "abc-123-def")
if cached:
return cached.result # Return immediately ✅
3. Server executes (if not cached)
order = await create_order(dto)
await repo.save(record) # Cache result for future requests
return order
4. Concurrent requests handled
If two requests arrive simultaneously:
- First request: cache miss → execute → save ✅
- Second request: collision on save → fetch first result → return ✅
Both requests get the same result - idempotency guaranteed!
Use cases
- HTTP APIs — ensure POST/PUT requests are idempotent
- Background Jobs — prevent duplicate processing on retries
- Event Consumers — handle duplicate events gracefully
- Message Queues — at-most-once message processing
Documentation
- Quick Start — get started in 5 minutes
- User Guide — detailed usage and patterns
- Architecture — design principles
- API Reference — complete API docs
Development
make install # uv sync --group dev
make check # ruff + mypy
make test-unit # unit tests (no Docker)
make test-integration # integration tests (Docker required)
make test # all tests with coverage
make docs-serve # local docs preview
See CONTRIBUTING.md for the full guide.
License
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file idempotency_kit-0.1.0.tar.gz.
File metadata
- Download URL: idempotency_kit-0.1.0.tar.gz
- Upload date:
- Size: 22.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.14 {"installer":{"name":"uv","version":"0.11.14","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d1056ec6af6645abcba19c532b7eecc6f5400253da54deea1dc5152633b39db2
|
|
| MD5 |
f5b01f7cd54df5eb0e694e071927c4cb
|
|
| BLAKE2b-256 |
acbfc97cfc86f442440094e639a3adb58df2fe04d14a311f57abea85702baecf
|
File details
Details for the file idempotency_kit-0.1.0-py3-none-any.whl.
File metadata
- Download URL: idempotency_kit-0.1.0-py3-none-any.whl
- Upload date:
- Size: 33.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.14 {"installer":{"name":"uv","version":"0.11.14","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
38368c2cbcbd80d3dd35f169b7bb467712941bb39e59cfd82b428e7c41a24d6c
|
|
| MD5 |
fd597620395e1613f7df2dbb4786e6a3
|
|
| BLAKE2b-256 |
3c62374a7f64a9d1b9103cc74ccda2dc4cb096ee12121f5f333c8362e29b7fbb
|