Ответ
Идемпотентность — это свойство операции, при котором повторный её вызов с теми же входными данными не изменяет состояние системы после первого успешного вызова. Проще говоря, f(f(x)) = f(x)
. Это критически важно для построения надёжных систем, особенно в условиях нестабильной сети, где клиент может повторно отправить запрос, не получив ответа.
Ключевые подходы к реализации:
-
Идемпотентный ключ (Idempotency Key)
Это самый распространённый и надёжный способ. Клиент генерирует уникальный идентификатор для каждой операции (например,
UUID
) и передаёт его в заголовке запроса (например,Idempotency-Key
).Алгоритм на стороне сервера:
- При получении запроса извлечь идемпотентный ключ.
- Проверить, обрабатывался ли запрос с таким ключом ранее.
- Если ключ новый: начать обработку. Перед изменением состояния системы сохранить ключ и результат операции в хранилище (например, Redis или БД). После этого вернуть результат клиенту.
- Если ключ уже существует: не выполнять операцию повторно, а сразу вернуть сохранённый результат из хранилища.
-
Хранилище для ключей
-
Redis: Идеально подходит благодаря атомарной операции
SETNX
(SET if Not eXists). Она позволяет установить значение, только если ключа ещё не существует.// Псевдокод с использованием Redis wasSet, err := redisClient.SetNX(ctx, idempotencyKey, "processing", 24*time.Hour).Result() if err != nil { /* обработка ошибки */ } if !wasSet { // Ключ уже существует, значит, запрос-дубликат // Нужно вернуть сохраненный ранее результат return getSavedResponse(idempotencyKey) } // Новая операция: выполняем логику, сохраняем результат и возвращаем его result := processRequest(request) saveResponse(idempotencyKey, result) return result
- База данных (SQL): Создаётся таблица для идемпотентных ключей с
UNIQUE
ограничением на столбец ключа. Попытка вставить дубликат вызовет ошибку, которую можно обработать.
-
-
Проверка состояния объекта
Иногда операцию можно сделать идемпотентной по своей природе. Например, операция
DELETE /users/123
идемпотентна: первый вызов удалит пользователя, а последующие просто вернут404 Not Found
, не меняя состояние системы. ОперацияSET user.status = 'active'
также идемпотентна.