Система с гарантированной доставкой сообщений: очереди, outbox и повторы без дублей

Заказ записан в базу, а в учёт не ушёл. Или ушёл дважды. Или пришла отмена раньше самого заказа. Это не редкие сбои, а обычное поведение сети и процессов, и обмен между вашими системами нужно строить так, чтобы это переживать. Мы проектируем и пишем такой обмен: сообщение записывается вместе с данными, доставляется до подтверждения, повтор не создаёт дубль, а то, что застряло, видно человеку. Где хватит простой схемы без брокера, так и скажем.

Обследование обмена — от 200 000 ₽, 2–3 неделиПроверка отказами: убиваем процесс между записью и отправкойИсходный код в вашем репозитории с первого коммита

С чем приходят

Когда обмену между системами нужна гарантия доставки

Запись есть, сообщения нет

Сервис сохранил заказ и упал до отправки в учёт. В базе заказ есть, в 1С нет, и узнают об этом по звонку клиента.

Заказ попал в учёт дважды

Отправка не получила ответа и повторилась, хотя первая дошла. Склад собрал два заказа, разбирать приходится вручную.

Порядок сообщений нарушен

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

Очередь есть, видимости нет

Сообщения копятся, часть обработчиков давно падает, и никто об этом не знает.

Где теряется

Шесть мест, где сообщение пропадает или двоится

Гарантия строится на каждом участке пути, а не в одном месте.

Участок пути
Что происходит
Как проявляется
Чем закрываем
Участок путиЗапись и отправкадва действия подряд
Что происходитСервис сначала сохраняет данные, затем отправляет сообщение
Как проявляетсяПроцесс падает между ними: данные есть, сообщения нет, и никто не знает об этом
Чем закрываемOutbox: сообщение пишется в ту же транзакцию, что и данные, а отдельный процесс отправляет его потом
Участок путиПередача посредникуотправитель и брокер
Что происходитОтправитель передаёт сообщение очереди и ждёт ответа
Как проявляетсяОтвет потерялся, отправитель повторил, в очереди два одинаковых сообщения
Чем закрываемИдентификатор сообщения, подтверждение приёма брокером, повтор с паузой
Участок путиХранение в очередиброкер перезапускается
Что происходитСообщения лежат в памяти или на диске посредника
Как проявляетсяПосле перезапуска часть сообщений пропала, потому что хранились в памяти
Чем закрываемДолговечные очереди, настройка записи на диск, проверка перезапуском на стенде
Участок путиЧтение получателемполучатель берёт сообщение
Что происходитПолучатель читает сообщение и начинает работу
Как проявляетсяПолучатель упал на середине; если подтверждение было раньше работы, сообщение потеряно
Чем закрываемПодтверждение после обработки, возврат необработанного в очередь по истечении срока
Участок путиОбработкаэффект в вашей системе
Что происходитПолучатель выполнил действие и не успел подтвердить
Как проявляетсяСообщение вернулось в очередь и действие выполняется второй раз
Чем закрываемInbox: обработанные идентификаторы запоминаются, повтор возвращает прежний результат
Участок путиПорядок и ожиданиесообщения обгоняют друг друга
Что происходитИзменение пришло раньше создания
Как проявляетсяОбработчик выбрасывает сообщение, которое «не к месту», и данные расходятся
Чем закрываемНомер версии записи, ожидание в очереди, отдельный список для разбора
Что значит «гарантированно»

Доставка один раз не бывает: бывает доставка хотя бы раз и обработка без дублей

Слово «гарантированная» легко понять как «ровно один раз». Так не бывает.

Сеть не отличает потерянное сообщение от потерянного ответа, поэтому выбрать «не терять и не повторять» нельзя. Для данных, которые нельзя терять (заказы, изменения остатков, документы), берётся схема «доставить хотя бы раз» и поверх неё защита от дублей. Эффект «ровно один раз» получается из двух частей: отправитель повторяет до подтверждения, а получатель узнаёт то, что уже обработал.

Три уровня гарантии и что за каждый платите

  • «Не больше одного раза». Отправили и забыли. Просто и быстро, но сообщения теряются. Годится для сведений, которые устареют через минуту: индикатор онлайна, показания, которые придут снова.
  • «Хотя бы один раз». Повторяем до подтверждения. Сообщения не теряются, но могут прийти дважды. Это основная схема для бизнес-данных.
  • «Один раз по эффекту». «Хотя бы раз» плюс получатель, который не выполняет повтор. Стоит дороже всего: нужны идентификаторы, хранилище обработанных, дисциплина в коде.

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

Что такое outbox и зачем он нужен

Основная ошибка обмена — два независимых действия подряд: записать в свою базу и отправить посреднику. Между ними всегда есть окно, в которое попадает падение процесса. Outbox убирает окно: сообщение записывается в таблицу той же базы в той же транзакции, что и данные. Либо есть и данные, и сообщение, либо нет ни того ни другого. Отдельный процесс читает таблицу, отправляет сообщения, ждёт подтверждения и только потом отмечает их отправленными. Если он упал, сообщения остались в таблице и будут отправлены после запуска.

Цена небольшая: одна таблица, один процесс-отправитель и дубли при повторах, которые закрывает получатель. Зато исчезает класс ошибок «заказ есть, сообщения нет». Выбор между очередью и событиями в архитектуре в целом описан на странице про микросервисы и высоконагруженные системы; здесь разбираем сам обмен.

Как получатель узнаёт повтор

Защита от дублей лежит на получателе: отправитель может только повторять. Получатель записывает идентификатор сообщения в базу в той же транзакции, что и результат, и повтор находит запись и возвращает прежний итог. Где есть бизнес-ключ, например номер заказа партнёра, дубль отсекает ограничение базы на повтор значения. Для передачи состояния хватает номера версии, а простые операции делаются так, чтобы повтор был безвреден: «установить статус», а не «изменить статус». Какой приём где, решаем по каждому типу сообщений.

Повторы и сбои

Повторы, карантин и разбор застрявших сообщений

Гарантия доставки без видимости превращается в тихую потерю. Поэтому вторая половина работы — то, что видит человек.

Как повторяем и когда сдаёмся

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

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

Экран разбора для человека

Человек, а не программист, должен видеть для каждого типа сообщения: что застряло, с какого времени, по какой причине и что можно сделать. Минимальный набор: список с фильтром по типу и возрасту, текст причины понятным языком, кнопки «повторить» и «отклонить с комментарием». Обмен с партнёрами в форматах оператора и AS2 вынесен отдельно, см. страницу про EDI-интеграции; здесь речь об обмене между вашими собственными системами и сервисами.

Сверка как последняя линия обороны

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

Посредник

Чем передавать: таблица в базе, RabbitMQ или Kafka

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

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

Как проверяем, что гарантия работает

Убиваем процесс в нужный момент

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

Повторяем одно и то же

Каждое сообщение отправляется дважды и трижды, в разном порядке; результат должен быть один. Обязательная часть приёмки для заказов и остатков.

Сверка на боевых данных

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

Что делаем

Из чего состоит работа и сколько она стоит

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

Обследование: один обмен

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

200 000 ₽ · 2–3 недели

Обследование: несколько систем

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

350 000 ₽ · 3–4 недели

Лёгкий пилот: один тип сообщений

Один поток, например заказы в учёт, с outbox, повторами, защитой от дублей и экраном разбора на реальных данных.

150 000–400 000 ₽ · 2–8 недель

Тяжёлый пилот: цепочка

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

400 000–1 200 000 ₽ · 2–3 месяца

Вывод в эксплуатацию

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

от 1 500 000 ₽ этапами по 300 000–700 000 ₽ · от 3 месяцев

Сопровождение

Мониторинг очередей и задержек, разбор инцидентов, плановые доработки с пакета на 60 000 ₽. Сверх пакета — 5 000 ₽ в час.

20 000 / 60 000 / 120 000 ₽ в месяц
Процесс

Как идёт работа

2–4 недели — Обследование: карта сообщений

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

Перед разработкой — Схема и контракты

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

От 2 недель — Пилот одного потока

Один тип сообщений проходит весь путь на реальных данных.

1–2 недели — Испытания отказами

Останавливаем процессы, повторяем сообщения, меняем порядок, накапливаем очередь. Результат записывается в протокол, который остаётся у вас.

Этапами — Перенос потоков

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

Дальше — передача или сопровождение

Регламент, мониторинг и инструкция передаются вам; сопровождение берём по договору с часами.

Цена

Что двигает цену внутри вилки

Число типов сообщений и участников

Десять потоков между пятью системами стоят больше, чем десять отдельных потоков: добавляются порядок, версии и общие справочники.

Возможности принимающих систем

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

Строгость гарантии

Чем больше потоков требуют обработки «один раз по эффекту», тем больше разработки и испытаний.

Состояние старого обмена

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

Контроль

Что остаётся у вас и чего мы не делаем

Остаётся у вас

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

Мы этого не делаем

  • Не обещаем «ровно один раз» на уровне сети: гарантия строится из повторов и защиты от дублей, и мы говорим об этом заранее.
  • Не строим платёжные и банковские системы и не принимаем платежи от вашего имени.
  • Не подключаем государственные системы и не заменяем системы управления технологическим процессом.
  • Не оказываем хостинг брокеров и не дежурим круглосуточно.
  • Не берём работы дешевле 150 000 ₽ и не вводим брокер там, где хватает таблицы в базе.
Граница

Гарантия доставки, EDI, интеграция 1С или события: где проходит граница

Если нужно связать учётную систему с сайтом и складом, начинают с интеграции 1С: там обмен проектируется под конкретные конфигурации. Если сообщения идут к внешним партнёрам в форматах оператора и по каналам вроде AS2, это EDI-интеграция. Если нужен интерфейс для чужих систем, смотрите разработку API и бэкенда.

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

Инструменты

На чём собираем

Обмен и данные
  • PostgreSQL: таблицы outbox и inbox, ограничения на повтор значений
  • RabbitMQ при росте потока и числа обработчиков; Kafka только когда нужен перечитываемый журнал
  • Python или Go для отправителя и обработчиков
  • Схемы сообщений с версиями, описание контрактов
Наблюдение и развёртывание
  • Метрики задержки очереди, числа попыток, возраста самого старого сообщения
  • Журналы с общим идентификатором сообщения
  • Docker, Nginx, GitLab CI
  • Стенд для испытаний отказами
Материалы

Материалы по теме

Статья

Проектирование API для интеграций: версии и ошибки

Как описывать ошибки, версии и повторы так, чтобы партнёр не получал дубли. Пригодится, если у вас внешний интерфейс.

  • Версии
  • Ошибки
  • Повторы
Читать →
Статья

Микросервисы или монолит: как выбрать

Какую сложность распределённости вы покупаете и когда обмен через сеть оправдан.

  • Цена сети
  • Критерии
  • Границы
Читать →
Статья

Не совпадают остатки 1С и маркетплейса: семь причин

Часть причин расхождений на самом деле относится к потерянным и задвоенным сообщениям.

  • Причины
  • Как искать
  • Что исправить
Читать →
Заявка

Разберём, где теряются или двоятся ваши сообщения

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

Спасибо, заявка отправлена. Ответим в течение рабочего дня.

Не удалось отправить. Напишите в телеграм или позвоните.

Вопросы

Частые вопросы: гарантированная доставка сообщений

Что значит гарантированная доставка сообщений?

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

Что такое outbox простыми словами?

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

Нужен ли для этого RabbitMQ или Kafka?

Не всегда. Для небольшого потока хватает таблицы в базе с процессом-отправителем. Брокер оправдан, когда много обработчиков, нужны приоритеты и отложенные повторы, а Kafka только когда поток нужно хранить и перечитывать.

Как защититься от дублей заказов?

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

Сколько стоит построить такой обмен?

Обследование — 200 000 ₽ за 2–3 недели (350 000 ₽ при нескольких системах), лёгкий пилот одного потока — 150 000–400 000 ₽, тяжёлый пилот с цепочкой и посредником — 400 000–1 200 000 ₽. Вывод в эксплуатацию — от 1 500 000 ₽ этапами. Обследование вычитается из первого этапа, если продолжаете с нами.

Можно ли улучшить обмен без переписывания систем?

Часто да. Outbox и защиту от дублей добавляют на границе: меняется способ записи и отправки, а не бизнес-правила.

Чем это отличается от EDI-интеграции?

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

Что с сопровождением обмена?

Ежемесячно: 20 000, 60 000 или 120 000 ₽ в месяц, до 4, 12 или 25 часов. Часы идут на мониторинг очередей и разбор застрявших сообщений; сверх пакета — 5 000 ₽ в час. Круглосуточной дежурной смены у нас нет.

Вы работаете только в Ростове-на-Дону?

Мы в Ростове-на-Дону, работаем с заказчиками по всей России: удалённо и в вашем контуре. Доступ к системам и обследование согласуем на старте с вашей службой безопасности.