Сайт принял заказ, менеджер не видит его в CRM, а покупатель уже спрашивает, когда будет доставка. В такой ситуации мало добавить ещё одно уведомление. Нужно понимать, где сохранён заказ, какие системы его получили и кто разбирает расхождения.
Интеграция — это согласованный обмен данными между программами. API позволяет одной программе обращаться к другой, но сам по себе не определяет правила работы бизнеса. Разберём эти правила на условном магазине оборудования: сайт принимает заказы, CRM помогает менеджерам, учётная система ведёт товарные данные. Это учебный пример, а не описание результатов проектов DDRW.
1. Сначала назначьте владельцев данных
Начать стоит с таблицы полей: название, источник, получатель, разрешённое направление изменения. Если цену одновременно меняют на сайте и в учётной системе, очередной обмен может затереть нужное значение. Тогда проблема находится в правилах владения данными, даже если соединение работает исправно.
В нашем примере сайт отвечает за описания и изображения, CRM — за назначение менеджера и этап общения, учётная система — за цены и доступное количество. Такая схема подходит не всем: в другом бизнесе каталогом управляет отдельная система, а цены рассчитывает специальный сервис. Важен явно выбранный источник каждого поля.
Отдельно определяем, что сайт показывает при недоступности источника. Допустимо ли временно показывать последнюю известную цену? Можно ли принять заявку на уточнение наличия? Кто подтверждает возможность выполнения заказа? Ответы должны появиться до подключения обмена.
Заказ сохраняет условия, которые были показаны и подтверждены при оформлении. Последующее изменение карточки товара не должно незаметно переписывать его состав. Если сотрудник меняет заказ, это отдельное действие с понятной историей.
Владелец бизнеса может проверить постановку простым вопросом: «Если сведения различаются, где мы ищем правильное значение?» Ответ «смотря какая программа обновилась последней» означает, что договорённости ещё не готовы.
2. Разделите объекты, события и статусы
Имя покупателя, телефон и номер строки в таблице неудобны для связывания записей. Человек меняет контакты, два заказа могут выглядеть одинаково, а сортировка списка постоянно меняется. Нужен устойчивый идентификатор — ID, который сохраняется на протяжении жизни объекта.
Пусть сайт создал заказ WEB-1042, CRM присвоила ему свой ID, а учётная система — ещё один. Интеграция хранит соответствие этих значений. Не обязательно заставлять все программы использовать один формат: необходимо уметь однозначно находить одну и ту же сущность.
У события тоже есть идентификатор. «Создан заказ», «изменён адрес» и «подтверждена оплата» относятся к одному заказу, но описывают разные факты. ID операции обозначает конкретное действие, которое программа пытается выполнить. Эти идентификаторы помогают разобраться, какой именно шаг повторился или остановился.
Не сводите всё к одному статусу «готово». Заказ может быть создан, но ещё не передан в CRM; платёж — ожидать подтверждения; доставка — не начинаться. Менеджеру полезно видеть эти состояния раздельно.
В нашем примере покупателю показывают, что заказ зарегистрирован на сайте. Внутри админки рядом видно: передача в CRM ожидается. Так подтверждение приёма заказа не превращается в необоснованное обещание завершённой обработки.
3. Сохраняйте заказ вместе с задачей на передачу
Опасная последовательность выглядит так: сохранить заказ, затем отправить его в CRM. Если приложение остановится между действиями, заказ останется на сайте без задачи на передачу. Обратная последовательность тоже неудобна: внешняя запись уже появилась, а локальная ещё не сохранена.
Один из подходов — transactional outbox, или журнал исходящих событий. Данные заказа и событие для дальнейшей доставки записывают в одной локальной транзакции: база фиксирует обе записи либо ни одной. Отдельный фоновый обработчик читает журнал и отправляет сообщения. Это не общая транзакция с CRM; получатель всё равно должен учитывать возможные повторы. Описание outbox в AWS Prescriptive Guidance.
Для владельца магазина практический результат такого устройства — возможность найти заказ и задачу, которая должна передать его дальше. В карточке операции можно показать время постановки, последнюю попытку, внешний ID и следующую запланированную попытку.
Состояние «передано» требует точного определения. Оно может означать, что внешний сервис принял запрос, но ещё не завершил внутреннюю обработку. Надпись в интерфейсе должна соответствовать этому смыслу.
Журнал не заменяет резервные копии и эксплуатацию сервера. Его задача в нашем примере — сделать исходящие действия частью управляемого процесса, а не случайным продолжением нажатия кнопки.
4. Подготовьтесь к таймауту после успешного действия
CRM может сохранить запись, а сайт не получить ответ вовремя. Таймаут означает отсутствие своевременного ответа, но не доказывает, что действие не выполнено.
Идемпотентность позволяет повторять одну операцию без дополнительного эффекта. Если API поддерживает такой контракт, отправитель сохраняет ключ операции и повторяет запрос с тем же ключом и теми же данными. Для нового намеренного действия нужен новый ключ. На стороне получателя проверка ключа, изменение данных и фиксация результата должны защищаться от конкурентной обработки; проверки «такая запись уже есть?» перед созданием недостаточно. Разбор идемпотентных API в Amazon Builders’ Library.
Для WEB-1042 первая и повторная попытки создания записи относятся к одному действию. Изменение состава заказа — уже другая операция. Нельзя незаметно заменить данные прежнего запроса и отправить его под старым ключом.
Название поля или заголовка, срок хранения ключей и поведение при конфликте берут из документации конкретного API. Наличие похожего механизма у другого сервиса ничего не подтверждает.
Если получатель не поддерживает безопасный повтор, после неоднозначного ответа нужна сверка по внешнему идентификатору, а иногда ручная проверка. Кнопка «повторить» в таком случае должна объяснять последствия, а не автоматически создавать новую запись.
5. Повторяйте временные ошибки, показывайте остальные
Повторы требуют ограничений по числу попыток и времени. Backoff означает увеличение паузы между попытками, jitter — случайную добавку к паузе. Это помогает не отправлять множество запросов одновременно после восстановления сервиса. Таймауты и политика повторов должны учитывать особенности операции. Рекомендации Amazon Builders’ Library.
Для ответа 429 ориентируются на правила ограничения запросов конкретного API. Если документация предусматривает Retry-After, обработчик учитывает указанное время. Ошибку обязательного поля или недействительные учётные данные обычно требуется исправить; повтор неизменного запроса сам этого не сделает.
В условном магазине неверный код товара выводится в очередь ошибок с понятным объяснением. Сотрудник видит WEB-1042, проблемное соответствие и допустимое действие. Пароли, токены и полный текст персональных данных в такой карточке не нужны.
После исчерпания попыток операция не должна исчезнуть. Ей назначают состояние, заметное ответственному сотруднику. Отдельно показывают старые зависшие задачи: очередь может двигаться, пока одна запись остаётся необработанной.
Повтор после исправления сохраняет связь с исходным заказом и историю попыток. Исправление содержания оформляют явно, учитывая контракт получателя, чтобы сотрудник понимал, что именно будет передано повторно.
6. Проверяйте входящие уведомления и их актуальность
Webhook — уведомление, которое внешний сервис отправляет вашему приложению при событии. Например, учётная система сообщает об изменении заказа. Открытый адрес приёма ещё не делает сообщение достоверным: нужны предусмотренные поставщиком проверки подлинности.
Способ проверки подписи, допустимое время сообщения и формат подтверждения определяет контракт сервиса. Например, Stripe описывает проверку подписи по исходному телу запроса, возможные повторные доставки и отсутствие гарантированного порядка событий. Это пример устройства конкретного провайдера, а не инструкция для CRM или Т-Банка. Документация Stripe о webhook.
Наш магазин должен различать повтор того же события и новое изменение заказа. При наличии версии объекта сравнивают именно версии этого объекта. Если контракт не даёт надёжного порядка, можно получать актуальное состояние через API и сверять его, соблюдая ограничения сервиса.
Иначе позднее уведомление о старом этапе способно вернуть заказ из состояния «передан в доставку» в прежнее состояние. Слепое применение сообщений по времени прибытия здесь не подходит.
Если интеграция допускает фоновую обработку, сначала надёжно сохраняют принятое событие и затем подтверждают приём согласно контракту. HTTP 200 подтверждает успешный HTTP-ответ; завершение бизнес-действия необходимо отслеживать отдельно. Непроверенное сообщение не должно менять заказ, а ошибка проверки должна быть видна оператору без раскрытия секретов.
7. Договоритесь, как обнаруживать и разбирать расхождения
Даже аккуратно спроектированный обмен нуждается в сверке. Для нашего магазина отчёт связывает локальный заказ с записями CRM и учётной системы: найдены ли они, совпадает ли состав, когда обновлялись, есть ли незавершённые действия. Сверка идёт по устойчивым ID, а не только по общему количеству заказов.
Важен возраст самой старой ожидающей задачи. Небольшая очередь может содержать давно забытый заказ. Дополнительно полезны число ошибок, время последней успешной передачи и расхождения, которые ещё не разобраны. Порог внимания выбирают под рабочий процесс бизнеса.
Назначьте ответственного и порядок действий: открыть операцию, проверить внешнюю запись, устранить причину, выбрать разрешённый повтор, убедиться в результате. Массовый повтор всей истории без разбора способен осложнить ситуацию.
Приёмку удобно оформить матрицей сценариев. Проверяют обычный заказ, недоступность CRM, потерянный ответ после сохранения, двойную доставку события, изменение порядка уведомлений, неверное поле и одновременную обработку одной операции. Для каждого случая заранее записывают ожидаемые состояния сайта и внешней системы.
Это проверяемые требования к проекту, а не обещание отсутствия любых сбоев. Хорошая интеграция помогает заметить проблему, объяснить её и восстановить согласованность данных контролируемым действием.
Чеклист перед запуском
- Для каждого поля определён источник и разрешённое направление изменения.
- Заказ связан с внешними записями устойчивыми идентификаторами.
- Создание, оплата, передача и выполнение отображаются отдельно.
- Исходящие операции сохраняются вместе с локальными изменениями.
- Правила повторов согласованы с контрактами подключённых API.
- Входящие уведомления проверяются до изменения бизнес-данных.
- Очередь ошибок и отставание видны назначенному ответственному.
- Сценарии сбоев включены в приёмку, а расхождения можно сверить по ID.
Частые вопросы
Нужно ли сразу связывать все системы?
Начните с одного законченного маршрута: от сохранения заказа до появления записи у менеджера. Опишите его ошибки и контроль, затем добавляйте следующие направления обмена.
Может ли уведомление в мессенджере заменить CRM?
Оно помогает привлечь внимание, но само по себе не показывает историю обработки и согласованность записей. Решение зависит от процесса: важно, где сотрудник принимает задачу и отмечает результат.
Что попросить показать подрядчика?
Один заказ целиком: локальную запись, связь с внешней системой, историю передачи, видимую ошибку и контролируемое восстановление. Это нагляднее демонстрации только успешного запроса.
