Интеграция систем: как связать 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 })
}Очередь сообщений
Система А кладёт сообщение в очередь, система Б забирает его, когда готова. Обмен перестаёт зависеть от одновременной доступности систем: если склад на техобслуживании, заказы просто ждут в очереди и обработаются позже.
| Ситуация | Подход |
|---|---|
| Нужен ответ немедленно | Прямой вызов |
| Внешний сервис сообщает о событии | Вебхук с проверкой подписи |
| Обмен между внутренними системами | Очередь сообщений |
| Массовая выгрузка за период | Плановая синхронизация по расписанию |
Что делает интеграцию надёжной
- Идемпотентность. Повторная обработка того же события не должна создавать дубль. Проще всего добиться уникальным индексом по идентификатору события.
- Повторные попытки с растущей паузой. Сетевые сбои кратковременны, разумная стратегия повторов закрывает большинство из них без вмешательства.
- Журнал обмена. Каждое отправленное и принятое сообщение сохраняется с результатом. Без журнала разбор инцидента невозможен.
- Очередь неудачных сообщений. То, что не удалось обработать за несколько попыток, откладывается для ручного разбора, а не теряется.
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 нужен там, где ответ требуется немедленно, вебхуки подходят для уведомлений о событиях, а обмен между внутренними системами лучше вести через очередь сообщений — тогда недоступность одной системы не останавливает остальные.
- Почему вебхуки приходят дважды и что с этим делать?
- Повторная доставка — нормальное поведение отправителя при неуверенности в получении ответа. Обработчик должен быть идемпотентным: уникальный индекс по идентификатору события делает повтор безопасным, а в ответ на повтор следует возвращать успех, чтобы отправитель прекратил попытки.
- Что нужно, чтобы интеграция была надёжной?
- Четыре элемента: идемпотентность обработчиков, повторные попытки с увеличением паузы, журнал всех отправленных и принятых сообщений и очередь неудачных сообщений для ручного разбора. Без журнала разбор инцидента «данные не дошли» практически невозможен.
- Когда нужна интеграционная шина вместо прямых связей?
- Мы вводим единую точку обмена начиная с четвёртой системы в контуре. При пяти системах прямых связей может быть до двадцати, и каждая новая система требует настройки обмена со всеми существующими. Через шину добавление системы — одна интеграция вместо пяти.
Похожая задача в вашем проекте?
Разберём вашу ситуацию и пришлём оценку по этапам — без обязательств и общих слов.
Обсудить задачу

