Привет! Меня зовут Артём, я бэкенд-разработчик. Продолжаю серию про Битрикс24. Сегодня — про вебхуки, которые кажутся простым и надёжным инструментом интеграции, но на практике скрывают несколько неприятных сюрпризов. Один из них чуть не стоил нам бизнесу.
История началась с простой задачи: синхронизировать сделки из Битрикс24 в нашу внутреннюю CRM. При создании или обновлении сделки Битрикс24 должен отправлять вебхук на наш сервер. Классика.
Настройка: казалось бы, ничего сложного
Заходим в CRM -> Настройки -> Вебхуки -> Входящий вебхук. Создаём обработчик для события ONCRMDEALADD и ONCRMDEALUPDATE. Указываем URL нашего endpoint, включаем обработку. Проверяем — приходит тестовый webhook, наш сервер обрабатывает, данные в CRM. Всё работает.
Запускаем в продакшен. Первые дни — всё отлично. Сделки создаются и обновляются, данные летят мгновенно. Через неделю — менеджер замечает, что в нашей CRM нет двух сделок, которые точно были созданы в Битрикс24. Проверяем логи на нашем сервере — вебхук на эти сделки не приходил. Проверяем в Битрикс24 — сделки существуют, но ни одного outbound webhook в логе.
Ограничение очереди: 1000 событий
После разбора с техподдержкой Битрикс24 выяснилось следующее. Вебхуки в Битрикс24 обрабатываются через очередь. Когда происходит событие (создание сделки), Битрикс24 добавляет его в очередь на отправку. Если очередь превышает 1000 событий, старые события удаляются без возможности восстановления. Это не задокументировано в основном мануале, и об этом легко не узнать, пока не столкнёшься с проблемой.
Как очередь может вырасти до 1000? Легко. Если ваш сервер упал на 10 минут (deploy, перезагрузка, DDoS), а в Битрикс24 за это время было создано или обновлено 1001 сделка — первые события будут потеряны. Если у вас крупный отдел продаж, это может произойти за 30 минут высокой активности.
Очередь вебхуков Битрикс24:
[1] ONCRMDEALADD #1234 -- обработан
[2] ONCRMDEALUPDATE #1234 -- обработан
[3] ONCRMDEALADD #1235 -- обработан
...
[998] ONCRMDEALADD #1499 -- ожидает отправки
[999] ONCRMDEALUPDATE #1498 -- ожидает отправки
[1000] ONCRMDEALADD #1500 -- ожидает отправки
[1001] ONCRMDEALADD #1501 -- УДАЛЁН! (очередь переполнена)
[1002] ONCRMDEALADD #1502 -- УДАЛЁН! (очередь переполнена)
Ещё хуже: события удаляются с «хвоста» очереди, то есть самые старые. Это значит, что потерянные сделки — самые ранние из «пакета», и если менеджер не заметит пропажу сразу, данные будут потеряны навсегда.
Лимит 2000 входящих вебхуков
Отдельное ограничение: на одном портале можно создать не более 2000 входящих вебхуков. Звучит как много, но если каждый модуль вашей системы создаёт свой вебхук для каждого типа сущности и события, вы упрётесь в лимит быстрее, чем думаете. У нас было 48 вебхуков на момент обнаружения проблемы, и лимит мы не превысили. Но если вы интегрируете много внешних систем, стоит считать.
Решение: Polling вместо Webhook (надёжный подход)
После инцидента мы отказались от входящих вебхуков и перешли на polling-модель: наш сервер сам регулярно опрашивает Битрикс24 на наличие новых изменений.
class BitrixDealSyncer
{
private string $lastSyncKey = 'bitrix_last_deal_sync';
public function sync(): void
{
$lastSync = $this->cache->get($this->lastSyncKey, date('Y-m-d H:i:s', strtotime('-1 hour')));
// Получаем сделки, изменённые с последней синхронизации
// Важно: в Bitrix24 REST API нет параметра 'limit', только 'start' для пагинации
$deals = $this->bitrixApi->call('crm.deal.list', [
'filter' => [
'>DATE_MODIFY' => $lastSync
],
'select' => ['ID', 'TITLE', 'STAGE_ID', 'DATE_MODIFY'],
'order' => ['DATE_MODIFY' => 'ASC'],
'start' => 0
]);
$lastProcessedDate = $lastSync;
foreach ($deals as $deal) {
$this->processDeal($deal);
$lastProcessedDate = $deal['DATE_MODIFY'];
}
// Обновляем timestamp только после успешной обработки всей пачки
if ($lastProcessedDate > $lastSync) {
$this->cache->set($this->lastSyncKey, $lastProcessedDate, 86400);
}
}
}
Запускаем этот скрипт каждые 2 минуты через cron. Метод crm.deal.list с фильтром по DATE_MODIFY возвращает только изменённые сделки. Если наш сервер упал на час — при следующем запуске cron подхватит все пропущенные сделки. Никаких потерь данных.
Оптимизация: пагинация и обработка больших объёмов
Метод crm.deal.list возвращает максимум 50 записей за запрос. Если за время downtime было изменено больше 50 сделок, нужно пагинировать через параметр start:
$allDeals = [];
$start = 0;
$lastProcessedDate = null;
do {
$batch = $this->bitrixApi->call('crm.deal.list', [
'filter' => ['>DATE_MODIFY' => $lastSync],
'select' => ['ID', 'TITLE', 'STAGE_ID', 'DATE_MODIFY'],
'order' => ['DATE_MODIFY' => 'ASC'],
'start' => $start
// параметр 'limit' в Bitrix24 REST API не поддерживается!
]);
if (empty($batch)) {
break;
}
foreach ($batch as $deal) {
$this->processDeal($deal);
$lastProcessedDate = $deal['DATE_MODIFY'];
}
$allDeals = array_merge($allDeals, $batch);
$start += 50;
} while (count($batch) === 50);
// Обновляем lastSync по последнему обработанному элементу
if ($lastProcessedDate) {
$this->cache->set($this->lastSyncKey, $lastProcessedDate, 86400);
}
Важно: не забывайте про rate limiting Битрикс24. Стандартный лимит — 50 запросов в секунду для REST API. При batch-обработке 200 сделок с пагинацией по 50 — это 4 запроса за раз, что безопасно. Но если вы параллельно синхронизируете и другие сущности (контакты, компании, задачи), общее количество запросов может превысить лимит.
Совет: для массовой обработки используйте batch-метод Битрикс24 — он позволяет отправить до 50 команд в одном запросе, что значительно снижает нагрузку и риск превышения лимитов.
Комбинированный подход: Webhook + Polling
В итоге мы остановились на комбинированной схеме. Вебхуки используются для «быстрой» синхронизации — когда сервер работает стабильно, данные приходят мгновенно через webhook. Polling (cron каждые 5 минут) используется как safety net — подхватывает события, которые не дошли по вебхуку.
Для предотвращения дублей каждое событие идентифицируется по хэшу: md5($eventType . ':' . $entityId . ':' . $timestamp). Если хэш уже обработан — событие пропускается. Это позволяет вебхуку и polling работать параллельно без конфликтов.
Важный нюанс: при создании вебхука указывайте параметр register_mode: 'S' (sync) или 'A' (async) в зависимости от критичности данных. Асинхронный режим надёжнее при пиковых нагрузках.
Главный вывод: не доверяйте вебхукам Битрикс24 как единственному каналу передачи данных. Всегда имейте fallback-механизм. Потерянные сделки — это потерянные деньги, и никто не будет извиняться за то, что «вебхук не долетел».
Пока нет комментариев
Будьте первым, кто оставит комментарий к этой статье