Идемпотетность. Самый бесполезный архитектурный спор
Redis или PostgreSQL для идемпотентности?
Что такое идемпотентность, и зачем она нужна см. в моём предыдущем посте "Двойное списание случается не потому, что кто-то ПЛОХОЙ ИНЖЕНЕР".
Вариант 1. PostgreSQL (Source of Truth)
Базовая схема.
Таблица idempotency_keys в реляционной БД, например, PostgreSQL.
Храним:
- key — PK, уникальный
- hash запроса (ловим подмену параметров)
- тело ответа
- статус ответа
- дату создания ключа (для аудита)
Пример таблицы:
Алгоритм:
- Начинаешь транзакцию
- INSERT ... ON CONFLICT DO NOTHING
- Если вставка прошла → ты первый → выполняешь платёж
- Если нет → возвращаешь сохранённый ответ
Ключевой момент: проверка + выполнение + сохранение результата — в одной транзакции. Иначе при параллельных запросах словишь двойное списание даже с ключом.
Логика на Go:
Redis: где полезен, а где подстава
Redis часто используют так:
- SET NX key → "забронировали ключ"
- сделали операцию
- записали результат
Проблема: если сервис упал между SET NX и сохранением результата — у тебя "processing" навсегда. И клиент будет ходить по кругу.
Поэтому в платежах Redis — это:
- либо ускоритель
- либо защита от горячих дублей
Но не источник истины.
Нормальная продовая схема
Комбо:
- Redis → быстро отсекает повторы в горячем окне (с коротким TTL)
- PostgreSQL → хранит результат и правду для аудита
Так ты получаешь:
- скорость
- надёжность
- возможность разруливать инциденты
На что смотреть в ревью
Чек-лист:
- есть ли Idempotency-Key в API (и он обязателен)
- хранится ли ответ, а не только факт запроса
- проверяется ли hash запроса
- всё ли в одной транзакции
- адекватный TTL (обычно 24ч–7 дней)
- есть ли cleanup
Вывод
Идемпотентность — это не "архитектурный паттерн ради галочки".
Это штука, которая отделяет:
мы делаем платежи
от
мы иногда списываем деньги дважды, но потом возвращаем
В финтехе второй вариант долго не живёт.