Что лучше для опроса статусов платежей, крон задача или отложенные сообщения через rabbitmq сервер?
Всем привет. На работе сейчас обсуждаем, как отрефакторить систему. Есть проблема. Ядро системы обращается к внутренним сервисам проведения платежей для инициализации платежа. Потом ядро начинает ходить за статусами платежей к этим сервисам, типа а вот такой платеж готов или нет? Сообщения о проверке статуса формируется ядром, это простое отложенное сообщение в очередь. Проблема в том, что ядро постоянно спамит проверкой статусов наши сервисы.
Есть два варианта решения проблемы, которые сейчас видим и оба из них предусматривает переделывали логики, так, чтобы адаптера сами разруливали ситуацию с опросом статуса и только когда нужно отправляли сообщение ядру.
Заранее уточню - колбек от оператора связи получает только один платежный сервис, другие операторы так не делают. Поэтому в этом сервисе все просто - получил колбек - отправил ядру уведомление.
У остальных операторов такой роскоши нет и мы пока вот два решения рассматриваем.
- Крон задача, которая работает на платежном сервисе и раз в какое-то время отправляет в очередь сообщение на запуск механизма проверки статуса платежа и отправки ответа ядру.
- Отложенные сообщения внутри платежного сервиса. Пришло сообщение на инициализацию платежа, мы его выполнили и в конце сразу отправляем отложенное сообщение на проверку статуса, которое почитается из очереди через нужное время.
У первого варианта вижу из недостатков это то, что по умолчанию обычная крон задача не может выполняться чаще 1 раза в минуту и нужно делать костыль с демоном или что-то прикручивать еще к киберу. Плюс она будет выполняться иногда в холостую, когда нет платежей не в финальном статусе, хотя это наверно мелочь? Из плюсов - простая логика, то есть очень легко отслеживать и понимать работу кода. Просто крон контроллер и нужные действия.
У второго варианта из минусов вижу, что нужно добавлять и в безрого запутанную логику дополнительные отправки сообщений в очередь на проверку статуса. Ведь у нас есть один платежный сервис, где логика не сводится к простому - отправил запрос на платеж и проверил статус. Тут надо и выпустить токен через aok, и проверить его статус и потом уже только провести платеж и его статус проверить. Плюс разные отмены и возвраты. Из плюсов - нет крон задач и бизнес логика в одном месте, плюс кроны в холостую не вызываются.
Для меня лично вроде крон задачи выглядят посимпатичнее, в том смысле, что ты знаешь что вот запрос пришел в сервис и все, дальше его статусы будут проверяться по крону и не надо нигде больше искать логику тайную, что-то рефакторить, все понятно, все лежит в одном месте. На счет того, что вызываться иногда будут в холостую, ну это все миллисекунды и в целом плевать. Но с другой стороны тут проблема появляется, что будет там не мало крон задач, одна на проверку платежа, другая токена, третья отмены, возврата и это уже каша может получиться. Но не так критично.
Второй вариант мне правда нравится тем, что он выглядит как-то более органично, чтоли. Ты отправляешь запрос на инициализацию платежа и сервис сам там по очередям себе раскидывает что надо. Но у него я еще вижу минус в том, что крон задача - это надежно. Пока она не доведет до нужного состояния платеж, она не успокоится. А вот отправка отложенных сообщений это возможные косяки - ты отправил в сервис запрос на инициализацию, у тебя оно пришло, сервис отправил платеж оператору, мы запушили отложенное сообщение о проверке статуса в очередь и вдруг у тебя сервер очередей лежал в это время? Или что-то в коде отвалилось и запрос не смог отправиться? И вот у тебя висит платеж. с нефинальным статусом, но его никто не попробует переподнять.
Может сочетать оба варианта и сделать задачи как подстраховку?
Вот хочу посоветоваться, какой из вариантов лучше и что бы вы предложили сами?
Ни тот и ни другой. Переходите на Message Driven архитектуру. Вместо того, чтобы делать постоянные запросы кроном к сервису лучше сделайте публикацию события в RabbitMQ.
В момент, когда платеж был выполнен публикуется интеграционное событие PaymentPaid. В это событие вкладываете все нужные данные, в том числе и ID по которым связываются платежи. Далее сервисы, которые заинтересованы в этих событиях подписываются на них и совершают нужные действия.
При работе с RabbitMQ нужно помнить:
Он гарантирует как минимум 1 раз доставить ваше сообщение. Это значит, что вполне может быть дубль и вам нужно быть готовым к этому. То есть делать идемпотентный консьюмер.
Сообщение может быть не доставлено по причине недоступности сервиса очередей, так же и сообщение может быть потеряно, в том числе из-за недоступности сервиса. Поэтому вам нужно гарантировать доставку через Outbox.