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

Разделите состояния, прежде чем повторять действие

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

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

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

Повтор передачи и изменение заказа — не одно и то же

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

Если клиент изменил состав заказа, возникает новая редакция и отдельное действие. Совпадения содержимого сообщения недостаточно для определения повтора: два разных заказа могут содержать одинаковые позиции. И наоборот, одинаковый ключ с разными данными — повод разобрать конфликт, а не молча принять одну из версий.

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

Матрица исходов: что известно и что делать

Все ситуации в таблице — учебные. В конкретной системе сначала проверяют её правила, доступные свидетельства и полномочия на восстановление.

Таблица 1 · Матрица исходов: что известно и что делать
СитуацияЧто известноЧто проверитьДопустимый следующий шаг
Отказ до записиПолучатель явно отклонил запрос на проверке данныхЧто запись действительно не создана и указанная причина относится к этой операцииИсправить данные; выполнить согласованную новую попытку
Запись создана, ответ потерянЗапись найдена у получателя, но отправитель её не подтвердилНомер операции, версию и результат записиПолучить или восстановить подтверждение; не создавать второй заказ
Не сработала следующая системаЗаказ есть в учёте, состояние склада не завершеноДоставлено ли сообщение складу и что там произошлоПродолжить только незавершённый шаг по предусмотренному порядку
Вмешался сотрудникПосле первоначальной передачи запись менялась вручнуюКто, что и на основании какой версии изменил; какой результат теперь нуженСогласовать расхождение и дальнейшее действие, не затирать правку повтором
Исход неизвестенЕсть таймаут или разрыв связи, но нет достаточного подтвержденияЗапись, журнал и историю операции на принимающей сторонеЗафиксировать неопределённость и выполнить сверку; не повторять вслепую
Пришли разные версииДля одного заказа обнаружены сообщения с разным содержимымПорядок версий и уже выполненные действияОбработать изменение по правилу версий либо передать конфликт ответственному

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

Когда полезен outbox

Один из источников расхождений — раздельное сохранение данных и отправка события. Изменение уже записано, а уведомление о нём не ушло. Паттерн transactional outbox связывает изменение данных с записью события в одной локальной транзакции; доставку затем выполняют отдельно. Он рассматривается в рекомендациях AWS для таких случаев двойной записи.

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

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

Компенсация не стирает произошедшее

Если цепочка выполнилась частично, иногда нужен обратный шаг: например, освободить резерв после отмены заказа. Но это новое действие со своими правилами, правами и возможностью отказа. Оно не равно возврату всей системы в состояние «до начала».

В учебном примере уже переданный на отгрузку заказ может требовать решения сотрудника. Нельзя просто снять статус в кабинете и считать, что склад отменил работу. Для каждого обратного действия нужно определить разрешённое состояние, подтверждение результата и дальнейший путь при неудаче. Такие правила полезно обсудить заранее, а не выводить из названия кнопки «Отменить».

Реестр расхождений вместо списка тревог

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

Например: «В учёте заказ найден; подтверждение склада не получено; проверку складской записи выполняет ответственный за обмен; закрываем после сопоставления состава и получения итогового состояния». Такая запись предметнее, чем «сбой интеграции, перезапустить».

Реестр не должен содержать пароли или полные копии клиентских документов. Для первичного разбора обычно достаточно технических идентификаторов и обезличенных примеров. Доступ к подробным данным и порядок их передачи согласуют отдельно.

Как проверить исправление

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

Если исправляется потеря ответа после записи, итогом должно быть восстановленное подтверждение той же операции без новой записи. Если проблема в неверных данных, повтор без исправления не должен скрывать причину. Ручное изменение проверяют отдельно: восстановление обмена не должно незаметно перезаписать согласованную работу сотрудника.

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

По теме: Договориться о событиях и очередях.

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

Разобрать сбой обмена.