мета-данные страницы
Различия
Здесь показаны различия между двумя версиями данной страницы.
Предыдущая версия справа и слева Предыдущая версия Следующая версия | Предыдущая версия | ||
agbis_idempotency [28.04.2022 14:32] Anatoly [Идемпотентность запросов] |
agbis_idempotency [31.05.2022 10:44] |
||
---|---|---|---|
Строка 1: | Строка 1: | ||
- | ====== Идемпотентность запросов ====== | ||
- | Можно ознакомится статьей от Яндекс: [[https://habr.com/ru/company/yandex/blog/442762/]] | ||
- | |||
- | ===== 1. Пишущая транзакция (на сервере) ===== | ||
- | |||
- | \\ | ||
- | ==== Агент ==== | ||
- | - Добавлены property | ||
- | - Himstat.IdempotencyText устанавливается на прямую (доступно на чтение и запись) | ||
- | - Himstat.IdempotencyHash устанавливается при установке IdempotencyText (доступно только на чтение) | ||
- | - uErrorRes добавлен тип Exception TIdenpotencyException | ||
- | * На примере запроса PayPlanOrders: | ||
- | - THimstatDM.ReplyWithPayPlanOrders | ||
- | - Himstat.IdempotencyText := Srvr.Request.Query.Text; Получаем IdempotencyText IdempotencyHash | ||
- | - Himstat.DoPayPlanOrders | ||
- | - QueryIdempotency Записываем в таблицу Hash и время | ||
- | - Нет таблицы IDEMPOTENCY_QUERY - выходим из проверки | ||
- | - получаем старый ОТВЕТ (предыдущего АНАЛОГИЧНОГО запроса) ИЛИ получаем ОТВЕТ="" - Идет запись | ||
- | - ОТВЕТ=null - пытаемся записать HASH | ||
- | - ERROR Присваиваем ОТВЕТ:="" - Идет запись | ||
- | - FINALY | ||
- | - (1) ЕСЛИ ОТВЕТ=null - то у нас уникальный запрос записанный в таблицу | ||
- | - (2) ЕСЛИ ОТВЕТ<>null - запрос не уникален - возбуждаем исключение TIdenpotencyException.Create(ОТВЕТ); | ||
- | - (1) UpdateIdempotency сохраняем ОТВЕТ в таблицу | ||
- | - (2) TIdenpotencyException | ||
- | - Если исключение содержит НЕ ПУСТОЕ сообщение то это ОТВЕТ и мы его отправляем повторно | ||
- | - Если исключение содержит ПУСТОЕ сообщение то снова возбуждаем TIdenpotencyException и отправляем как ошибку ОДНОВРЕМЕННОГО ЗАПРОСА (ErrorCode = 5) | ||
- | - Если ОШИБКА произошла в теле обработки до сохранения ОТВЕТа то HASH запроса удаляется | ||
- | \\ | ||
- | ==== Клиент ==== | ||
- | - Организовать уникальность запроса | ||
- | - Обработку ErrorCode = 5 | ||
- | |||
- | ===== 2. Читающая транзакция (на на клиенте) ===== | ||
- | На примере МП Courier\\ | ||
- | |||
- | <code pascal> | ||
- | ... | ||
- | |||
- | ... | ||
- | var | ||
- | PayIdempotency: string;/ /'Переменная сохраняет состояние текущей транзакции /запрос(dor_id, debet) + ответ(JSON)/' | ||
- | ... | ||
- | |||
- | ... | ||
- | JSONAnswer := KassaFiscalRegistar.PrintFiscalCheck(JSONResultObj); / /'Печать чека' | ||
- | ... | ||
- | except | ||
- | on E: Exception do | ||
- | begin | ||
- | PayIdempotency := ''; / /'Если ошибка при печати - обнуляем текущую транзакцию' | ||
- | ... | ||
- | |||
- | ... | ||
- | procedure TmoneyPayFramePanel.OnShow(curVisible: TuniFramePanel); | ||
- | begin | ||
- | PayIdempotency := '';/ / 'При входе обнуление предыдущей транзакции' | ||
- | ... | ||
- | |||
- | ... | ||
- | ClnDM.GetFiscalCheck(sJSON, | ||
- | procedure (AJObject: TJSONObject) | ||
- | var CurrentPayIdempotency: string; / /'Текущая транзакция' | ||
- | begin | ||
- | CurrentPayIdempotency := THashMD5.GetHashString(sJSON + '=' + AJObject.ToString); | ||
- | if PayIdempotency = CurrentPayIdempotency then / /'Текущую сравниваем с запомненой' | ||
- | begin | ||
- | / / 'Ничего не делаем если транзакция все еще ТА ЖЕ' | ||
- | WriteLog("TmoneyPayFramePanel.WorkOfPay PayIdempotency = CurrentPayIdempotency Abort"); | ||
- | end | ||
- | else | ||
- | begin | ||
- | / /'Транзакция другая - выпонить оплату' | ||
- | PayIdempotency := CurrentPayIdempotency; | ||
- | AnswerFromWeb('GetFiscalCheck', '', 0, AJObject); | ||
- | end; | ||
- | end); | ||
- | ... | ||
- | |||
- | ... | ||
- | </code> | ||
- | |||
- | |||
- | Обращаться: | ||
- | [[user:OlegZuev|Олег Зуев]] |