🌤
📍 Определение...
📅 22.10.2026
👤 13
← Назад к новостям

Что происходит после пятой попытки? Эскалация застрявших платежей вместо бесконечного цикла

Неделю назад я писал о платеже, который застрял в статусе PENDING , и о исправлении, которое я отправил: задание по сверке, которое отмечает платеж как выполненный только после подтверждения того, что клиент действительно получил то, за что заплатил, а не раньше.

Читатель, Михай Пердум, оставил комментарий к этому сообщению, на который у меня в то время не было хорошего ответа: существует ли количество повторных попыток или возрастной порог, который отправляет кому-то сообщение, если выполнение неоднократно терпит неудачу структурно, а не временно?

Не было.

Задание, которое я отправил, повторяло неудачный платеж каждые пять минут, навсегда, без различия между «в базе данных был сбой, попробуйте еще раз» и «это событие было удалено и никогда больше не будет существовать, прекратите попытки».

Платеж, застрявший по структурным причинам, будет тихо зацикливаться, пока не выйдет из окна очистки и не исчезнет без предупреждения.

Это исправление, и что его тестирование дало мне о моей первой попытке.

Пробел Вот форма задания из последнего поста: try { await onPaymentSettled (оплата); жду БД. оплата . обновление ({где: {идентификатор: платеж. идентификатор}, данные: {статус: 'УСПЕХ'} }); } catch ( err ) { // возвращается в состояние ОЖИДАНИЕ, повторяет попытку следующего тика } В этом коде каждая ошибка выглядела одинаково: зарегистрируйте ее, оставьте в ОЖИДАНИИ, повторите попытку через пять минут.

Это верно для временного сбоя — тайм-аута, разрыва соединения.

Это неправильно для всего, что никогда не будет успешным при повторной попытке: удаленное событие, распроданный уровень билетов, внешний ключ, который больше не разрешается.

Им не нужно терпение, им нужен человек.

Исправление: подсчитать, классифицировать, эскалировать Два дополнения.

Счетчик попыток и классификатор, который отличает «попробуй еще раз» от «остановись и скажи кому-нибудь». } catch (err) {const попытки = оплата.

Попытки выполнения + 1 ; const структурный = isStructuralFailure (ошибка); const эскалация = структурный || попытки >= MAX_FULFILMENT_ATTEMPTS ; жду БД. оплата . update ({ где: {id: платеж. id}, данные: {fulfilmentAttempts: попытки, LastFulfilmentError: String (err. message). срез (0, 500), ... (эскалация && { NeedAttention: true }), }, }); если (эскалация) {ожидание notifyAdmins (платеж, ошибка); } } Запрос на очистку исключает все, что отмечено флагом NeedAttention , поэтому эскалированный платеж перестает автоматически повторяться и вместо этого остается там, где человек действительно его увидит.

Где моя первая версия ошиблась Задача классификатора — решить, какие ошибки являются структурными.

Мой первый проход: функция isStructuralFailure (err) {return err. name === 'PrismaClientValidationError' || ошибаюсь. код === 'P2025'; } Я протестировал его на реальном синтетическом сбое (платеж, ссылающийся на несуществующее событие), ожидая немедленного обострения ситуации.

Вместо этого: ❌ Не удалось выполнить платеж OTV-TEST-RETRYCAP-A (попытка 1, временная попытка) — возврат к режиму ОЖИДАНИЕ для повторной попытки Еще четыре идентичных сбоя позже: ❌ Не удалось выполнить платеж OTV-TEST-RETRYCAP-A (попытка 5, временная попытка) — ЭСКАЛАТАЦИЯ, требует ручного вмешательства Это обостряется, но только после исчерпания всего бюджета повторных попыток на чем-то, что никогда бы не смог добиться успеха.

Фактическая ошибка представляла собой простой код 404, выданный кодом приложения, а не ошибку Prisma вообще, поэтому мой классификатор ее не распознал.

Исправлено: функция isStructuralFailure (err) {const httpStatus = typeof err. getStatus === 'функция'? ошибаюсь.

Получить Статус (): 0; return ( ( httpStatus >= 400 && httpStatus < 500 ) || err . name === 'PrismaClientValidationError ' || err . code === ' P2025 ' || err . code === ' P2003 ' || err . code === ' P2002 ' ); } Тот же тест, перестроенный: ❌ Не удалось выполнить платеж OTV-TEST-RETRYCAP-A (попытка 1, структурная) — ЭСКАЛАТИЗАЦИЯ, требует вмешательства вручную Одна попытка вместо пяти.

Урок: классификатор — это утверждение о том, как выглядят ваши ошибки, и единственный способ узнать, верно ли это утверждение, — это бросить в него настоящее утверждение и посмотреть.

Убедитесь, что предупреждение не отображается дважды.

Доставки и повторные попытки Webhook могут повторно войти в путь сбоя после того, как платеж уже помечен.

Без охраны уже эскалированный платеж приведет к

📊 Источник: dev.to | Оригинал
← Предыдущая Тесты мобильного пользовательского интерфейса в YAML: без сервера WebDriver, без установки драйверов Следующая → Статья, которую вы не хотите видеть в своем отчете о последствиях: когда вызов не дает результатов