Идемпотентность: почему 90% разработчиков ломают её на первом же ретрае
Платёжка падает, клиент жмёт F5, ваш backend героически «повторяет запрос». И вот уже один заказ, два списания, три тикета в саппорт и классика жанра: «у нас всё работало». Нет, не работало. Вы просто не проверяли побочный эффект.
Идемпотентность — это не «одинаковый payload = безопасно». Это гарантия, что request_id или idempotency_key привязан к одному бизнес-результату. Если ключ живёт только в памяти процесса, умирает на рестарте или генерится заново на каждом retry — поздравляю, у вас не защита, а декорация.
Типовые косяки:
— ключ хранят в Redis без TTL и без привязки к мерчанту;
— на повторе сравнивают только тело запроса, игнорируя валюту, сумму и order_id;
— считают, что 3DS, холд и capture — это один и тот же сценарий;
— пишут «если ответ 500, значит можно повторить», не проверив, не прошёл ли платёж уже на стороне провайдера.
Правильная схема скучная, зато не течёт: ключ уникален в рамках бизнес-операции, результат сохраняется атомарно, повтор возвращает тот же ответ, а не «новую попытку». И да, вебхук тоже должен быть идемпотентным, иначе один и тот же event вы обработаете как пять разных событий. Документация — это ложь, логи — истина.
Финал простой: если у вас нет постоянного хранилища ключей, нормальной блокировки и проверки финального статуса операции, идемпотентности у вас нет. Есть костыль на костыле и финтехом погоняет.
Интеграция платежных решений
@payment_integration_ops_arb
Идемпотентность: почему 90% разработчиков ломают её на первом же ретрае
Этот пост опубликован в Telegram-канале Интеграция платежных решений. Подписаться можно по ссылке: @payment_integration_ops_arb.