Idempotency
Idempotent — операция, которую можно повторить N раз и результат будет как при однократном выполнении. Критично для сетевых API: клиент может retry-ить после таймаута, а сервер должен не задублировать эффект.
HTTP-методы
| Метод | Idempotent? | Safe? |
|---|---|---|
| GET | да | да |
| HEAD | да | да |
| OPTIONS | да | да |
| PUT | да | нет |
| DELETE | да | нет |
| POST | нет | нет |
| PATCH | зависит | нет |
Idempotency-Key header
Клиент генерит UUID перед POST. Шлёт как Idempotency-Key: uuid. При retry — тот же key.
POST /payments HTTP/1.1
Idempotency-Key: 07e5f210-...uuid
Content-Type: application/json
{"amount": 100, "to": "user_42"}
Логика на сервере
- Пришёл запрос с Idempotency-Key.
- Проверяешь: этот key уже видел?
- Да → вернуть сохранённый ответ (не выполнять повторно).
- Нет → выполнить, сохранить ответ + key на N дней.
Атомарность
Ключевой момент: сохранение key и выполнение операции должны быть атомарны. Иначе race: два параллельных retry могут оба увидеть "нет" и оба выполнить.
# SQL upsert-подход
INSERT INTO idempotency_keys (key, status) VALUES (?, 'processing')
ON CONFLICT (key) DO NOTHING RETURNING *;
# если RETURNING пусто — уже кто-то обрабатывает
TTL
Ключи не хранят вечно. Обычно 24 часа - 30 дней. Stripe — 24 часа. Достаточно для retry.
Кто использует
- Stripe — эталон (docs)
- Amazon (AWS) — SDK автоматически ставят client-token
- Square, PayPal, Adyen
- Kubernetes API — resourceVersion для optimistic locking
Natural idempotency
Иногда возможно без ключа: PUT (полная замена → повтор безопасен), DELETE (удалить дважды = удалить один раз).
Idempotency vs Deduplication
- Idempotency — клиент шлёт key, чтобы retry не задублировал
- Deduplication — сервер сам решает, что запрос дубль (по content-hash)