Что такое идемпотентность задачи? Почему это важно?
Подробный ответ
Что такое идемпотентность
Задача идемпотентна, если её запуск один или несколько раз приводит к одному итоговому состоянию. Например, операция «установить статус заказа в paid» идемпотентна, а операция «увеличить баланс на 100» без дополнительной защиты — нет.
Почему дубликаты возможны
Исполнитель может успеть выполнить задачу, но аварийно завершиться до подтверждения брокеру. Тогда брокер считает задачу необработанной и передаёт её повторно. Повтор также возможен из-за retry, сетевой ошибки или слишком короткого времени видимости задачи в Redis.
Опасный пример
@shared_task
def add_bonus(user_id: int, amount: int) -> None:
user = get_user(user_id)
user.balance += amount
user.save()При повторном запуске баланс увеличится дважды.
Идемпотентный вариант
@shared_task
def apply_bonus(user_id: int, operation_id: str, amount: int) -> None:
if bonus_operation_exists(operation_id):
return
with transaction.atomic():
create_bonus_operation(
operation_id=operation_id,
user_id=user_id,
amount=amount,
)
increment_user_balance(user_id, amount)Уникальное ограничение на operation_id в базе данных предотвращает повторное применение одного и того же начисления.
Способы сделать задачу идемпотентной
передавать уникальный идентификатор операции и хранить факт обработки;
использовать уникальные ограничения базы данных;
проверять текущее состояние перед изменением;
использовать операции установки состояния вместо повторного добавления;
применять идемпотентный ключ при вызове внешнего платёжного или почтового сервиса.
Как ответить на собеседовании
Идемпотентная задача безопасна при повторном запуске: итоговое состояние не меняется после первого успешного выполнения. Это важно, потому что очереди обычно допускают повторную доставку. Для защиты использую идентификатор операции, уникальное ограничение в БД, проверку текущего статуса и идемпотентные ключи во внешних вызовах.
Оцени свой прогресс