Гарантированная доставка сообщений: очереди, retry и история транзакций
· Автор: Команда SmartConnect
Как проектировать доставку сообщений при сбоях интеграции: подтверждения, идемпотентность, ограниченные retry, журнал транзакций и проверка восстановления.
Что означает гарантированная доставка
При интеграции корпоративной системы с внешним сервисом самый сложный результат — неопределённый. Запрос ушёл, но ответ не пришёл. Система могла выполнить операцию, могла отклонить её, а могла ещё не начать обработку. Повторная отправка без проверки способна создать дубль; отказ от повторной отправки оставляет операцию незавершённой.
Поэтому разговор о гарантированной доставке стоит начинать с границ ответственности. Команда должна определить, что именно считается успехом: сохранение сообщения, приём посредником, получение внешним сервисом или подтверждённое выполнение бизнес-операции. Для проверки справочной информации и для создания операции эти условия будут разными.
В этом материале рассматривается рекомендуемая архитектура надёжного обмена. Конкретные механизмы нужно сопоставлять с контрактом выбранного сервиса и возможностями используемого шлюза.
Сначала договоритесь о подтверждениях
У сообщения несколько этапов пути. Оно создаётся в исходной системе, принимается интеграционным слоем, передаётся получателю и обрабатывается. На каждом переходе нужно понимать, кто отвечает за сохранность и какое подтверждение фиксирует передачу ответственности.
В RabbitMQ подтверждение публикации и подтверждение обработки потребителем решают разные задачи. Подтверждение брокера не доказывает, что конечное приложение выполнило бизнес-операцию. Это разделение подробно описано в документации RabbitMQ о подтверждениях.
Для интеграционного проекта полезно составить собственную таблицу подтверждений:
| Событие | Что нужно зафиксировать | Какой вопрос остаётся |
|---|---|---|
| Запрос создан | Идентификатор операции и исходное намерение | Принят ли он интеграционным слоем? |
| Запрос принят | Надёжно сохранённое состояние | Получил ли его внешний сервис? |
| Ответ получен | Транспортный и прикладной результат | Завершена ли бизнес-операция? |
| Операция подтверждена | Итог по контракту получателя | Нужна ли сверка с исходной системой? |
Это проектная модель, а не описание статусов конкретного API. Названия состояний и критерии успеха команда согласует до реализации.
Зачем нужна очередь
Очередь помогает разнести приём запроса и его последующую обработку. Например, корпоративное приложение может зафиксировать задание, а отдельный обработчик отправит его, когда внешний сервис станет доступен. Пользовательский процесс при этом должен видеть честный промежуточный статус.
Однако очередь требует эксплуатационных решений. Где сохраняются сообщения? Что произойдёт после перезапуска? Когда сообщение можно удалить? Что делать при переполнении? Сколько времени допустимо хранить устаревшее задание? На эти вопросы нельзя ответить одним названием брокера.
RabbitMQ рассматривает надёжность как общую ответственность брокера, отправителей и потребителей. Для проекта это означает необходимость проверять весь маршрут, включая приложение, хранилище и восстановление после отказа.
Если запрос справочный и чувствителен к актуальности, его поздняя обработка может потерять смысл. Для такого сценария следует определить срок полезности результата. Для операции с побочным эффектом важнее сохранение идентичности бизнес-намерения и возможность выяснить фактический исход.
Retry: какие повторы допустимы
Повторять запрос стоит по явной политике. Она должна учитывать тип операции, контракт получателя, общий срок выполнения и число уже сделанных попыток. Политика «повторять всё» скрывает ошибки данных и увеличивает нагрузку во время сбоя.
В AWS Builders’ Library разобраны тайм-ауты, повторные попытки, увеличение интервалов и случайная задержка. Авторы отдельно отмечают: тайм-аут не означает отсутствия побочного эффекта, а повторы могут усилить перегрузку.
Практический шаблон решения для команды:
| Ситуация | Рекомендуемое действие при проектировании |
|---|---|
| Данные не соответствуют схеме | Исправить данные; автоматический повтор того же сообщения не планировать |
| Нет разрешения на операцию | Проверить доступ; не создавать бесконечную очередь повторов |
| Ответ не получен | Сначала оценить возможность уже выполненной операции |
| Получатель временно недоступен | Применить согласованный ограниченный retry, если операция безопасна для повтора |
| Достигнут предел попыток | Зафиксировать итог и передать в управляемое разбирательство |
Классификация здесь концептуальная. Реальные коды и допустимые действия определяет контракт конкретного сервиса. Для интеграции с ШЭП/SmartBridge нельзя переносить значения и правила одного сервиса на другой без проверки его документации. Отсеять заведомо некорректные данные до постановки в очередь помогает проверка формата по XSD-схеме.
Команда также должна назначить один слой, управляющий повторами. Если приложение, шлюз и клиентская библиотека независимо повторяют запросы, фактическое количество вызовов становится трудно предсказуемым. Общий бюджет времени должен включать ожидание, обработку и интервалы между попытками.
Идемпотентность: сохраните одно бизнес-намерение
Идемпотентность нужна там, где повторная доставка допустима, а повторный бизнес-эффект нежелателен. Для проекта следует определить ключ операции: какое намерение он идентифицирует, кто его создаёт и сколько хранится результат проверки.
Разберём условную заявку на создание операции. Первый запрос получил ключ operation-123, но клиент не дождался ответа. При повторе с тем же ключом система должна распознать прежнее намерение согласно согласованному контракту. Если для каждой попытки создавать новый ключ, связать их с одной заявкой будет сложнее.
Это пример проектного требования. Перед внедрением нужно проверить, поддерживает ли получатель ключ идемпотентности, поиск результата по идентификатору или иной механизм сверки. Локальная защита от дублей в шлюзе сама по себе не доказывает защиту на стороне внешней системы.
Отдельно согласуйте поведение при одновременных повторах и при совпадении ключа с другим содержимым. Нужно также определить, что произойдёт после истечения срока хранения ключа. Эти условия входят в контракт интеграции и программу испытаний.
Журнал транзакций: как восстановить картину
Для эксплуатации полезна история, которая связывает исходную заявку, каждую попытку и итоговый результат. Её задача — помочь ответить на конкретные вопросы: где остановился обмен, что подтверждено и какое действие безопасно выполнить дальше.
Рекомендуемый минимальный состав записи: идентификатор бизнес-операции, идентификатор попытки, сервис, время, длительность, состояние и классификация ошибки. Добавляйте ссылку на результат или его защищённое хранилище, если это необходимо для согласованного сценария разбора.
Содержимое журналов проектируют отдельно от диагностической ценности. Доступы, сроки хранения и маскирование должны учитывать состав данных. Для интеграций с персональными данными особенно важно заранее согласовать, какие поля действительно нужны сотруднику поддержки. Ключи подписи, токены и секреты не должны попадать в диагностические записи — о безопасной работе с ключами см. отдельный разбор как устроена ЭЦП в Казахстане.
Неудачные задания следует направлять в отдельный управляемый поток разбора — например, в карантин или очередь ошибок, если это поддерживает архитектура. Повторный запуск должен оставлять новую запись в истории, сохранять связь с исходной операцией и требовать понятного основания.
Что проверять на испытаниях
Успешный обмен при доступном сервисе проверяет только основной сценарий. До промышленного запуска подготовьте сценарии отказа и заранее определите ожидаемый результат каждого.
- Остановить обработчик после сохранения задания. Проверить состояние после восстановления.
- Смоделировать выполнение операции без получения ответа клиентом. Проверить сверку результата и защиту от повторного эффекта.
- Отправить несколько одинаковых запросов одновременно. Убедиться, что система соблюдает согласованный контракт идемпотентности.
- Передать некорректные данные. Проверить, что ошибка не запускает бесконечные повторы.
- Сделать получателя недоступным дольше допустимого срока. Проверить завершение попыток и маршрут разбирательства.
- Выполнить ручной повтор. Убедиться, что есть автор действия, причина и связь с первоначальной записью.
Для каждого испытания сохраняйте наблюдаемые результаты. Формулировка «сообщение не потерялось» недостаточна без указания точки сохранения и подтверждения итоговой обработки.
Метрики для эксплуатации
Рекомендуем отслеживать число незавершённых заданий, возраст самого старого задания, долю операций с повторами, количество неопределённых исходов и время их разрешения. Для потока разбора полезны размер очереди и время до ответственного действия.
Пороговые значения назначают под бизнес-процесс. Справочный запрос, который нужен в текущей пользовательской сессии, и фоновая синхронизация имеют разные сроки полезности. Высокая доля успешно отправленных сообщений не заменяет метрику подтверждённого результата.
При обсуждении интеграции через Smartconnect подготовьте перечень операций, последствия дубля, допустимый срок ожидания и требования к истории. Это даст предметную основу для технической спецификации.
CTA: Запросите техническую спецификацию Smartconnect для вашего сценария: обсудим границы подтверждений, правила повторов и требования к восстановлению обмена.
Частые вопросы
Можно ли считать HTTP 200 подтверждением выполнения? Нужно прочитать контракт: успешная транспортная передача может сопровождать прикладную ошибку или означать только приём задания.
Нужна ли очередь для каждой интеграции? Решение зависит от допустимой задержки, характера операции и требований к восстановлению. Для синхронного сценария также нужны тайм-ауты и работа с неопределённым результатом.
Можно ли обещать отсутствие дублей только благодаря retry? Такое обещание требует отдельного доказательства. Нужно проверить контракт идемпотентности и поведение всех участников обмена при отказах.