Metadata-Version: 2.4
Name: kasper-idempotent
Version: 0.1.0
Summary: Idempotency-key decorator for exactly-once handlers, backed by Redis or in-memory.
Author-email: Kunta Mallik Raj <kuntamallikraj@gmail.com>
License: MIT
Project-URL: Homepage, https://github.com/KuntaMallikRaj
Keywords: idempotency,exactly-once,redis,decorator,deduplication
Classifier: Programming Language :: Python :: 3
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Provides-Extra: redis
Requires-Dist: redis>=4.2; extra == "redis"
Dynamic: license-file

# kasper-idempotent

Decorate a handler with an idempotency key. Duplicate calls (retries, at-least-once queues) return the stored result instead of running again.

```bash
pip install kasper-idempotent          # in-memory store
pip install "kasper-idempotent[redis]" # + Redis store (multi-process)
```

```python
from kasper_idempotent import idempotent, RedisStore

store = RedisStore("redis://localhost:6379")

@idempotent(store=store, key=lambda evt: evt["id"], ttl=3600)
def handle(evt):
    charge_card(evt)      # runs once per evt["id"], even on retries
    return {"ok": True}
```

## How it works
On call it atomically claims the key (`SET key ... NX`):
- **claim wins** -> run the handler, store the result, return it.
- **already done** -> return the cached result (no re-run).
- **in progress** -> raise `InProgress` (a concurrent duplicate is still running).

The atomic claim is what prevents two simultaneous duplicates from both executing. Sync and async handlers are both supported.

MIT licensed.
