Успешный платеж, который так и не стал бронированием

Клиент оплатил. Razorpay показал успех. Webhook отправил HTTP 200. Платеж был подтвержден (captured).

Тем не менее, статус бронирования застыл на «confirming».

Ошибок не было. Исключений в коде не возникало. Алерты не срабатывали. Все метрики показывали, что система работает исправно.

Но у клиента ничего не было. У автора не было бронирования.

Принимать деньги — легко. Обеспечить, чтобы каждый платеж приводил к бронированию — вот настоящая задача.

Большинство туториалов предлагают следующий процесс:

Это опасно. Если бизнес-логика находится внутри webhook, вы полностью зависите от успешности доставки. Webhook-и подвержены повторным попыткам (retries), дублированию и частичным сбоям.

Мы изменили архитектуру, чтобы разделить эти задачи. Теперь webhook-и только записывают события. Они не выполняют бизнес-логику.

Мы внедрили журнал событий (event ledger) с тремя таблицами:

Теперь у webhook-а одна задача:

Это защищает систему. Если webhook даст сбой, событие все равно будет в безопасности.

Мы также поняли, что состояние платежа и состояние бронирования — это разные вещи. Подтвержденный платеж (captured payment) — это входные данные. Подтвержденное бронирование — это результат. Разделение этих состояний позволяет проводить сверку (reconciliation).

В ходе расследования мы обнаружили баг. События были в базе данных. Процессор работал исправно. Webhook работал исправно.

Но процессор никогда не запускался. Никто не вызывал функцию для обработки ожидающих событий.

Разделение приема данных (ingestion) и их обработки — это правильный дизайн. Но это создает новое требование: что-то должно запускать процесс обработки.

Мы внедрили планировщик (scheduler) для выполнения нескольких задач:

Чтобы избежать ошибок при повторных попытках, мы используем следующую логику:

Система, которая работает только тогда, когда каждый webhook приходит вовремя — это хрупкая система. Если в вашей очереди некому вычитывать задачи, работа будет ждать вечно.

Надежность означает проектирование с учетом того, что сбои неизбежны.

Source: https://dev.to/abhishekvoid/a-successful-payment-that-never-became-a-booking-building-a-fault-tolerant-payment-pipeline-4ioj