Сервисы разделены по модулям, к которым относится данный функционал, будь то ../api/
, ../security/
или ../schedule/
Поэтому возможны смежные названия сервисов (как **AttachmentsService
) , но при этом сервисы работают для разных задач,
ограниченные рамками модулей
Реализовывать отдельное оповещение нет необходимости, потому что закладываемся, что мерчант настроит получение вебхуков
по ивенту корректировки и webhook-dispatcher
сам узнает об этом ивенте о пошлет уведомление
Модуль внешнего доступа для создания диспутов и опроса статуса. Все действия проходят через БД, проактивного запроса к
провайдерскому API
не происходит. Создание диспута означает лишь создание записи в БД, решение далее принимается на
уровне модуля ../schedule/
Перед созданием нового диспута проверяем, существует ли уже какой либо открытый по данному платежу, потому что открытым может быть только один за раз, если существует, отдаем действующий
(реализации на данный момент нет) Передача uniqID на создании\статусе диспута дает возможность проверять наличие диспута (через опрос статуса) до этапа создания с внешнего вызова
При ошибках сервис кидает:
5хх
, если это отказ внешних шлюзов404
, если это отсутствие данных400
, если это ошибка в данных запросов401
, если это отсутствие прав для доступа кAPI
При опросе диспута существует несколько значений параметра ErrorMessage
, при которых информация об диспуте не отдается
и наружу выкидывается 404
. Такое поведение возникнет, если в другом потоке шедулатора
при обработке диспута возникли
ошибки\отказ внешних шлюзов с ключевыми данными и в рамках данного диспута проблема является непреодолимой. Единственным
способом решить данную проблему будет создание нового диспута.
Модуль с шедулаторами
, которые по расписанию обрабатывают диспуты.
Все процессы в шедулаторах
проходят в изоляциях транзакций, при исключениях возникает откат.
При обработке диспутов шедулатор
блочит используемые айдишники на уровне запроса к базе.
Диспут у провайдера не будет создан, пока платеж находится в не финальном статусе, это ограничение на уровне hellgate
.
Когда статус платежа
становится captured|cancelled|failed
разрешена дальнейшая обработка диспута.
Не все провайдеры на данный момент поддерживают работу с диспутами по API
.
Предполагается такой способ действия при этой ситуации:
- При наличии диспутов по
API
у провайдеров в терминале добавляется опция —DISPUTE_FLOW_PROVIDERS_API_EXIST
- если эта опция терминала есть, то сервис ищет роут до адаптера и отправляет запрос по трифт протоколу, иначе будет пулять в топик\тг-провайдер-бот\filebeat
- если возникнет ошибка роута, то будет пулять в топик\тг-провайдер-бот\filebeat
Используется экспоненциальный пуллинг, после которого мы считаем, что диспут протух и поллить его не надо.
Опция DISPUTE_FLOW_MAX_TIME_POLLING_MIN
контролирует максимальное время пуллинга
Диспуты на проверку статуса упорядочиваются по последнему времени проверки поля next_check_after
, берутся самые
древние
Ответственность за актуальный статус диспута несет конкретный адаптер. Решение остается за адаптером, тк детали
реализации могут отличаться в зависимости от интеграции, disputes-api
работает уже с результатом этого процесса и
занимается обновлением статуса диспута в своей БД. При этом, при создании диспута необходимо в адаптере по возможности
проверять наличие существующего диспута, в случае отказа внешних шлюзов после вызова ручки создания диспута на адаптере.
Если по какой то причине на этапе опроса статуса шедулатор
не найдет в БД актуальную запись об
конкретном provider_dispute_id
(т.е. диспут в адаптере не был создан), то обработка диспута будет возвращена на этап
назад, для попытки создать диспут в адаптере заново.
Перед созданием корректировки сервис пытается найти уже созданные корректировки и найти среди них существующую
корректировку и при успехе переводит диспут в успех. Этот процесс ликвидирует ситуацию дублей корректировок.
В идеале, после создания корректировки диспут переводится в успех.
Данная реализация предусматривает, что сервис при обработке не зависнет в неопределенном состоянии, а если это произойдет, то это не повлияет на состояние данных
Критичные внешние шлююзы:
postgres
[RW] (хранение данных по диспутам)hellgate
[RW] (запись корректировок)file-storage-v2
[RW] (хранение файлов чеков диспутов)dominant
[R]bouncer
[R]token-keeper-v2
[R] (авторизация по токену)
В модуле API
при падении внешних узлов в общей цепочке вызовов будет откат транзакции, данные в БД не запишутся,
диспут не будет создан и наружу вернется выбранный http-код
В модуле Schedule
при падении внешних узлов в общей цепочке вызовов будет откат транзакции, данные в БД не запишутся,
а также продусмотрена проверка hellgate
, существует ли уже такая корректировка
Запись file-storage-v2
не регулируется на уровня транзакции сервиса, но конкретно в случае file-storage-v2
возможность повторной записи не является критичным фактором
Вызов адаптеров — пулинг на падения не влияет, но при создании предполагается, что это ответственность адаптера удостовериться, что такого диспута еще не существует.
схема такая: после создания диспута через нашу внешнюю апишку, будет происходить несколько кейсов:
- если
CreatedDisputesService
при попытке создать диспут в провайдере понимает, что такой ручки в провайдере не существут, отправляет на ручной разбор - если не выставлен флаг в опциях
DISPUTE_FLOW_PROVIDERS_API_EXIST
, то тоже отправляет на ручной разбор
Далее, через внутрений трифт-интерфейс саппорт получает способ манипулировать диспутом для его
обработки (AdminManagementDisputesService
)
- Перед переводом диспута в финальный статус саппорт должен будет забиндить айди созданного диспута в провайдере через
ручку
BindCreated()
. Здесь особенность, что этот метод фильтрует возможность биндить диспуты только созданные вручную (изalready_exist_created
)
Далее, в режиме ручного разбора есть опция финализации диспута в фейл (CancelPending()
) либо в
успех (ApprovePending()
). Здесь особенность, что в фейл можно перевести любой диспут имеющий не финальный статус, а в
успех можно перевести, только если гарантировано создан внешний диспут у провайдера (
из pending
,manual_pending
)
- Из за того, что для ручных диспутов добавлены отдельные
статусы
manual_pending
не происходит ситуации, что такие диспуты попадут в таскуPendingDisputesService
которая автоматически вызывает апи провайдера для проверки статуса
Добавить в БД для диспута колонку "IS_AUTO", по дефолту проставляем туда FALSE. Получаем успешный статус от провайдера, пишем в БД статус READY_FOR_ADJUSTMENT. Корректировки проводим в отдельном потоке по расписанию, как сейчас создаем и проводим диспуты (просто последний вариант разбиваем на два отдельных). По расписанию стартует поток и автоматически проводит только те проводки, где IS_AUTO = TRUE. В идеале саппорт/фины будут скриптом/в админке сначала проставлять TRUE.