Deployment¶
Version pinning¶
drf-idempotency>=1.0,<2.0
Supported runtime versions¶
| Dependency | Supported |
|---|---|
| Python | 3.10, 3.11, 3.12, 3.13 |
| Django | 4.2, 5.0, 5.1, 5.2 |
| Django REST Framework | 3.14+ |
| redis (optional) | 5.0+ |
Database backend: migrations¶
python manage.py migrate drf_idempotency
This creates one table, drf_idempotency_idempotencyrecord. It has no
foreign keys into your own schema, so it can be migrated independently of
your application's own models.
Scheduling cleanup¶
The database backend has no native TTL — expired records are treated as absent on read, but still occupy storage until removed. Schedule the cleanup command periodically:
Cron:
0 * * * * cd /path/to/project && python manage.py cleanup_expired_idempotency_keys --quiet
Celery beat: define a task that wraps the command, then schedule it:
# tasks.py
from celery import shared_task
from django.core.management import call_command
@shared_task
def cleanup_idempotency_keys() -> None:
call_command("cleanup_expired_idempotency_keys", quiet=True)
# settings.py
CELERY_BEAT_SCHEDULE = {
"cleanup-idempotency-keys": {
"task": "myapp.tasks.cleanup_idempotency_keys",
"schedule": crontab(minute=0), # hourly
},
}
Not needed for RedisBackend — Redis expires keys natively via EX.
Redis deployment considerations¶
- Use a separate Redis logical database (
BACKEND_OPTIONS: {"url": "redis://host:6379/N"}) or a distinctkey_prefixfrom your caching/ session Redis usage, so idempotency keys can't collide with unrelated keys and can be reasoned about/monitored independently. - Idempotency records are small and short-lived (bounded by
TTL_SECONDS) — memory footprint scales with your idempotent-request volume ×TTL_SECONDS, not indefinitely. - If Redis is unavailable,
RedisBackendcalls will raise a connection error from the underlyingredisclient — idempotency handling is not designed to silently degrade to "no idempotency" on backend failure, since that could mean silently allowing double-processing. Monitor Redis availability as you would for any other critical dependency.
Rolling out to an existing API¶
- Add
drf_idempotencytoINSTALLED_APPSand migrate (database backend) — no behavior changes yet. - Add
IdempotencyMiddleware(or the decorator on specific views) withREQUIRE_KEY: False(default) — clients that don't send the header are completely unaffected. - Update client SDKs/integrations to send
Idempotency-Keyon retryable requests. - Once adoption is confirmed (e.g. via logging how many requests arrive
without the header), consider enabling
REQUIRE_KEY: Truefor endpoints where double-processing risk justifies making it mandatory.