Как стать автором
Обновить

Комментарии 15

У вас реализация неправильная. Если два запроса придут практически одновременно, то каждый вызовет _idempotencyRecordProvider.Get , ничего не получит и пойдёт обрабатывать запрос. Как минимум там надо создать пустую запись, которая показывает, что другой запрос уже начал обрабатываться, но ещё не закончил.

Тоже обратил на это внимание. По-хорошему там должна быть транзакция, в рамках которой происходит поиск по idempotencyKey и в случае отсутствия, вставка записи с этим идентификатором (естественно, также должен быть unique constraint в БД). В этом случае гонка уже не страшна, поскольку проверка и добавления записи с idempotencyKey атомарно.

Или блокировка на вставку. Но только пост не про это. Но раз есть запрос, подумаю над дополнением с обзором методов синхронизации, спасибо

форма на клиенте могла бы генерировать некоторый ключ на этапе заполнения и затем использовать его в запросе сохранения заказа

без модификации логики приложения

Вижу противоречие.


Сама идея генерировать токены для запросов не нова (см xsrf токены), но, кажется, в случае с дубликатами проблему нужно решать на стороне клиента (почему клиент успевает N раз нажать на кнопку прежде чем она станет disabled?).


А что если клиент хотел именно дубликаты, а вы лишили его этой возможности?
Приложение должно вежливо уточнить хочет ли он сделать дубликат (что-то в духе "Мы уже обрабатываем заказ с таким составом, добавить выбранные продукты к текущему, или оформить отдельный?").


Вот это вот "запрос клиента может не выполниться, если сервер посчитает его дубликатом, и никто не будет считать это странным поведением" — попахивает уже by design, ведь по сути вы закэшировали ответ на POST запрос к API (которое, скорее всего, REST).

почему клиент успевает N раз нажать на кнопку прежде чем она станет disabled?

Например мышка у клиента с дребезгом контакта на левой кнопке. Щелкает он один раз, а браузер получает 2-5 кликов за 1 милисекунду. Javascript просто не успевает дернуть обработчик первого клика чтобы отметить кнопку как disabled.

Это реальный кейс.

как человек с таким реальным кейсом в принципе компом пользуется? это ж не выделить объект никак - сразу только запуск, и кейсов где это доставит мягко говоря неудобства - масса.

не кажется, что это та проблема, которую стоит решать на уровне костылей

При увеличении количества клиентов где-то до 50k вероятность столкнуться с таким поведением оборудования стремится к 1. И вот у вас в базе два заказа с разницей во времени в 1 мс.
А что если клиент хотел именно дубликаты, а вы лишили его этой возможности?Приложение должно вежливо уточнить хочет ли он сделать дубликат (что-то в духе "Мы уже обрабатываем заказ с таким составом, добавить выбранные продукты к текущему, или оформить отдельный?").

Для реализации этого поведения понадобится сделать в общих чертах то, что описано в статье. Ключик завести уникальный, проверять его на сервере, и т.д.

Я не говорю, что в статье всё гладко и там всё сделано идеально, но общий смысл таков, что идемпотентность приходится делать.

Смотри шире, это же не только про форму и пользователя. В довольно стандартной интеграции микросервисов через transaction outbox одна из основных вещей - воспроизводимость и идемпотентность.

НЛО прилетело и опубликовало эту надпись здесь

Ничего не мешает возвращать любой ответ, "если ничего не поменялось", в случае PUT и POST. Код должен быть 412, да, а тело — любым.

Спасибо, хорошая идея для улучшения ​

Зачем чинить то что не ломалось?

Тут в самом начале PUT описан как "изменить", хотя он "поместить", а для "изменить" есть PATCH.

А по тексту по сути PUT /<guid> {body} превратили в POST / {guid, body} - ну такое

Да, можно и через PUT, но с его использованием возможна накладка с ID ресурса.

a) PUT/id = set (if doesn’t exist then throw), POST + idempotency key = create if doesn’t exist

b) PUT/id = if doesn’t exist then create else set. ID ресурса будет генерироваться клиентом. И тогда для изоляции клиентов понадобится уникальность id в рамках клиента (чтобы клиент вовсе не знал о других клиентах), либо требовать от клиентов глобальной уникальности используемых id (как с username на некоторых сайтах).

Весь пост ждал, когда дойдёт до описания механизма создания idempotency key _на клиенте_, но как раз этого момента совсем нет. AFAIU, для этой проблемы бы сработал любой рандом id, генерящийся при открытии формы .

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации