Владимир Синявский Инженер следующего изменения Каждое решение меняет цену следующего.

vsinyavsky.ru / инженерные расследования

Я разбираю инженерные решения по тому, что они делают дорогим потом.

Здесь реальные технические истории превращаются в интерактивные расследования. Вы восстанавливаете причинную цепочку, принимаете два решения и видите, как их порядок меняет цену следующего изменения.

Протокол 001

Три списания. Одна бронь.

14:47 Финансы

"У клиента три списания за один перелёт, а бронь одна. Что происходит?"

Booking: Failed

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

Рабочая версия, не установленный факт.

Основано на реальном инциденте. Идентификаторы и участники обезличены.

Хронология причин

  1. Первая попытка: Failed появился последним

    • 14:32:08 Booking BookingDraft → Pending
    • 14:32:09 Providers Первый перелёт создан
    • 14:32:11 Providers Отель забронирован
    • 14:32:14 Providers Второй перелёт → 409
    • 14:32:14 Booking BookingDraft → Failed

    Версия не выдерживает фактов: Failed появился после двух завершённых шагов.

    Если часть поездки уже существует, почему клиент запустил процесс снова?

  2. Интерфейс: завершённые шаги не показаны

    • 14:32:14 Interface Реконструкция интерфейса "Ошибка. Попробуйте снова."
    • Interface Первые завершённые шаги не показаны.

    Повтор выглядит как продолжение той же операции.

  3. Повтор: новый запрос стал новой операцией

    • через 45 с HTTP Новый запрос
    • Booking Предыдущая попытка не распознана
    • Providers Новая попытка снова падает на третьем сегменте

    Это отдельная попытка. Новое нажатие начало бизнес-операцию заново.

    Что каждая попытка сделала с деньгами?

  4. Payment: каждая попытка начала движение денег

    • Attempt 1 Payment pre-auth
    • Attempt 2 Payment pre-auth
    • Attempt 3 Payment pre-auth

    Экран предложил повторить → повтор стал новой операцией → уже завершённые шаги не были учтены → каждая попытка снова начала движение денег

Установленная причина

  1. Экран предложил повторить
  2. повтор стал новой операцией
  3. уже завершённые шаги не были учтены
  4. каждая попытка снова начала движение денег

Причина установлена. Дальше – архитектурный сценарий, а не продолжение хронологии инцидента.

Намерение клиента – одна поездка, которую он пытается оформить. Повторный HTTP-запрос не обязан означать новую поездку.

Что ограничить первым?

  1. Рубеж A

    Не создавать новую операцию при повторе

    Ограничивает появление новых попыток для того же намерения. Уже созданные сегменты, движение денег и неопределённость их состояния остаются открытыми.

  2. Рубеж B

    Компенсировать совершённые шаги

    Начинает ограничивать текущие последствия отдельными компенсирующими действиями. Новые попытки и неопределённость состояния остаются открытыми.

  3. Рубеж C

    Зафиксировать состояние и владельца

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

Шесть маршрутов, три состояния

Ниже – все возможные маршруты. Это карта решений, а не выбранный результат.

Повторы закрыты, компенсация запущена, процесс не виден

Система перестала создавать повторные операции и начала компенсировать совершённые шаги. Support всё ещё собирает состояние по нескольким системам, а сбой компенсации может оставаться незаметным, пока его не найдёт человек.

Следующее дорогое изменение: Явное состояние процесса, владелец следующего действия и видимая граница передачи человеку.

  1. Не создавать новую операцию при повторе Компенсировать совершённые шаги

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

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

  2. Компенсировать совершённые шаги Не создавать новую операцию при повторе

    Компенсация началась, пока повторный вход оставался открытым. Цена ожидания второго рубежа – риск получить ещё одну попытку, которую компенсации придётся разбирать отдельно.

    Новые повторы закрыты, поэтому набор операций перестал расти. Следующий рубеж всё ещё должен собрать их состояния и владельцев, но теперь работает с ограниченным набором попыток, а не с движущейся целью.

Повторы закрыты, процесс виден, компенсация не запущена

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

Следующее дорогое изменение: Компенсация фактов, которые уже произошли.

  1. Не создавать новую операцию при повторе Зафиксировать состояние и владельца

    Новые попытки больше не размножаются. Состояние и владелец следующего шага строятся вокруг одного намерения клиента, а не вокруг растущего набора повторов.

    Теперь видно, какие факты уже произошли и кто владеет следующим шагом. Компенсацию проще диагностировать, но она ещё не запущена, поэтому текущие последствия остаются срочной работой.

  2. Зафиксировать состояние и владельца Не создавать новую операцию при повторе

    Явное состояние операции даёт точку корреляции. Повторный HTTP-запрос можно связать с уже начатым намерением, а работу защиты проверить по состоянию процесса.

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

Компенсация запущена и видима, повторный вход открыт

Компенсации видимы и управляемы, но новый HTTP-запрос всё ещё может начать ещё одну бизнес-операцию. Восстановление разбирает последствия, пока источник повторов остаётся открытым.

Следующее дорогое изменение: Связать повторные запросы с одним намерением клиента.

  1. Компенсировать совершённые шаги Зафиксировать состояние и владельца

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

    Явное состояние даёт повторному запросу точку корреляции. Защита от новой операции ещё не внедрена, но её границу и результат теперь проще определить и проверить.

  2. Зафиксировать состояние и владельца Компенсировать совершённые шаги

    До запуска компенсаций уже известны состояние и владелец каждого шага. Сбой обратного действия не теряется в общем Failed и получает явную границу передачи человеку.

    Компенсации стали частью видимого процесса, а повторный вход остался открыт. Новая попытка теперь расширит и набор прямых фактов, и объём работы по их последующей компенсации.