Перейти к основному содержанию
Разработка3 мин чтения

Интеграция систем: как связать CRM, склад и сайт без хаоса

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

Схема интеграции сервисов с очередью сообщений

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

Три способа связать системы

Прямой вызов

Система А обращается к API системы Б и ждёт ответа. Просто в реализации и уместно, когда ответ нужен немедленно: проверка остатка на складе перед оформлением заказа. Недостаток очевиден — если Б недоступна, операция в А не проходит.

Вебхук

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

Идемпотентный обработчик вебхука
export async function POST(request: Request) {
  const event = await request.json()

  // Проверка подписи: без неё обработчик принимает
  // запросы от кого угодно
  if (!verifySignature(request, event)) {
    return new Response("Invalid signature", { status: 401 })
  }

  // Повторная доставка — нормальное поведение, а не сбой.
  // Уникальный индекс по event_id делает повтор безопасным.
  const inserted = await db.webhookEvents.insertIfAbsent({
    id: event.id,
    type: event.type,
    payload: event,
  })

  if (!inserted) {
    // Уже обработали ранее: отвечаем успехом, чтобы отправитель
    // прекратил повторы
    return new Response("Already processed", { status: 200 })
  }

  await handleEvent(event)
  return new Response("OK", { status: 200 })
}

Очередь сообщений

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

Когда что применять
СитуацияПодход
Нужен ответ немедленноПрямой вызов
Внешний сервис сообщает о событииВебхук с проверкой подписи
Обмен между внутренними системамиОчередь сообщений
Массовая выгрузка за периодПлановая синхронизация по расписанию

Что делает интеграцию надёжной

  1. Идемпотентность. Повторная обработка того же события не должна создавать дубль. Проще всего добиться уникальным индексом по идентификатору события.
  2. Повторные попытки с растущей паузой. Сетевые сбои кратковременны, разумная стратегия повторов закрывает большинство из них без вмешательства.
  3. Журнал обмена. Каждое отправленное и принятое сообщение сохраняется с результатом. Без журнала разбор инцидента невозможен.
  4. Очередь неудачных сообщений. То, что не удалось обработать за несколько попыток, откладывается для ручного разбора, а не теряется.
Повторы с увеличением паузы
export async function withRetry<T>(
  operation: () => Promise<T>,
  attempts = 4,
): Promise<T> {
  let lastError: unknown

  for (let attempt = 1; attempt <= attempts; attempt++) {
    try {
      return await operation()
    } catch (error) {
      lastError = error
      // Ошибки клиента повторять бессмысленно: данные не изменятся
      if (error instanceof HttpError && error.status < 500) throw error

      // Пауза растёт: 1, 2, 4 секунды. Случайная добавка
      // разводит одновременные повторы
      const delay = 1000 * 2 ** (attempt - 1) + Math.random() * 300
      await new Promise((resolve) => setTimeout(resolve, delay))
    }
  }

  throw lastError
}

Ошибка проектирования: связи «каждый с каждым»

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

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

Частые вопросы

Как связать CRM, склад и сайт между собой?
Выбор способа зависит от сценария: прямой вызов API нужен там, где ответ требуется немедленно, вебхуки подходят для уведомлений о событиях, а обмен между внутренними системами лучше вести через очередь сообщений — тогда недоступность одной системы не останавливает остальные.
Почему вебхуки приходят дважды и что с этим делать?
Повторная доставка — нормальное поведение отправителя при неуверенности в получении ответа. Обработчик должен быть идемпотентным: уникальный индекс по идентификатору события делает повтор безопасным, а в ответ на повтор следует возвращать успех, чтобы отправитель прекратил попытки.
Что нужно, чтобы интеграция была надёжной?
Четыре элемента: идемпотентность обработчиков, повторные попытки с увеличением паузы, журнал всех отправленных и принятых сообщений и очередь неудачных сообщений для ручного разбора. Без журнала разбор инцидента «данные не дошли» практически невозможен.
Когда нужна интеграционная шина вместо прямых связей?
Мы вводим единую точку обмена начиная с четвёртой системы в контуре. При пяти системах прямых связей может быть до двадцати, и каждая новая система требует настройки обмена со всеми существующими. Через шину добавление системы — одна интеграция вместо пяти.
интеграцииархитектураAPIбизнес-процессы

Похожая задача в вашем проекте?

Разберём вашу ситуацию и пришлём оценку по этапам — без обязательств и общих слов.

Обсудить задачу

Вопрос по статье
или по своему проекту

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

Написать нам

Поля со звёздочкой обязательны для заполнения.