Пользователь нажал кнопку один раз, а в Битрикс24 появились два лида. Закрывать это только поиском дублей в CRM рано: сначала надо понять, где именно запрос размножился. Браузер мог отправить форму дважды, обработчик сайта мог повторить вызов после таймаута, очередь могла забрать одно сообщение двумя воркерами, а интеграция могла два раза вызвать crm.lead.add.
Первое, что я бы сделал: выбрал одну форму, одно контрольное обращение и зафиксировал точное время до секунды. Пока этого нет, в логах будет десяток похожих телефонов, и команда начнёт спорить не о том запросе.
Сначала определите, какие именно записи считаются дублями
Сравните время создания, телефон, email, источник, страницу отправки и ответственного. Две записи с одинаковым телефоном, созданные с разницей в секунду, обычно указывают на повторную обработку одного события. Записи с разными источниками и интервалом в несколько часов могут быть двумя самостоятельными обращениями.
| Что видно | Рабочая гипотеза | Следующая проверка |
|---|---|---|
| Две записи в одну секунду | Двойной POST или повтор обработчика | Network и access log |
| Интервал совпадает с timeout | Автоматический retry без идемпотентности | Лог очереди и интеграции |
| Один телефон, разные формы | Два реальных входа либо неверная атрибуция | URL страницы и UTM |
| В CRM один лид, но две задачи | Повтор сработал после создания сущности | Автоматизация и журнал действий |
Проверка 1. Браузер отправляет один запрос или два
Откройте страницу формы в Chrome, затем DevTools → Network. Включите Preserve log, очистите список запросов и отправьте форму один раз. Отфильтруйте Fetch/XHR и найдите запрос обработчика. В Headers сохраните Request URL, метод и статус; в Payload проверьте, что ушли ожидаемые поля. Секреты вебхука и реальные персональные данные в снимок не включайте.
PASS: в Network появился один POST, кнопка стала недоступна на время отправки, ответ пришёл один раз. FAIL: видны два одинаковых POST с близким временем или обработчик вызван одновременно из submit и click.
Проверка 2. Сколько запросов увидел веб-сервер
Если браузер показал один POST, идём на сервер. Сначала узнайте фактический путь access log из конфигурации Nginx. Не предполагайте, что файл всегда лежит в одном каталоге.
sudo nginx -T 2>&1 | grep -n "access_log"
# Подставьте найденный путь и реальный endpoint формы
sudo grep 'POST /api/lead' /var/log/nginx/access.log | tail -n 20
Сопоставляйте строки по времени, IP, пути и коду ответа. Если приложение добавляет request_id, используйте его: один идентификатор должен проходить через веб-сервер, приложение, очередь и адаптер Битрикс24.
PASS: один пользовательский submit дал одну строку POST и один request_id. FAIL: access log содержит два POST или один POST породил два разных вызова интеграции.
Проверка 3. Не повторяет ли обработчик запрос после таймаута
Типичная поломка выглядит так: Битрикс24 успел создать лид, но сайт не дождался ответа. Код считает операцию неуспешной и отправляет тот же payload ещё раз. Для метода создания сущности повторный вызов — это новая операция. Поэтому retry без собственного ключа операции опасен.
Добавьте внутренний ключ обращения до вызова CRM, например UUID, и сохраните его вместе со статусом обработки. Повтор с тем же ключом должен вернуть уже известный результат, а не снова вызывать создание лида. HTTP-заголовок Idempotency-Key можно использовать только как часть собственного контракта endpoint: он не станет работать автоматически, если сервер не хранит ключи и не проверяет payload.
{
"request_id": "6f5c2d8e-...",
"form": "callback",
"status": "crm_created",
"crm_entity_id": 12345
}
PASS: повторная доставка с тем же request_id возвращает сохранённый результат и не создаёт вторую сущность. FAIL: каждый retry снова вызывает crm.lead.add.
Проверка 4. Очередь и воркеры
Если форма сначала пишет событие в очередь, проверьте подтверждение обработки. Сообщение нельзя подтверждать до успешной фиксации результата, но и запускать два воркера без блокировки одной задачи нельзя. В журнале должны быть видны идентификатор сообщения, номер попытки и итоговый ID сущности CRM.
PASS: один message_id обрабатывается последовательно, повторная попытка видит сохранённый request_id. FAIL: два воркера одновременно берут одно сообщение или результат CRM не записывается до повторной доставки.
Рабочий алгоритм без гадания
- Создайте одно контрольное обращение с уникальной пометкой.
- Проверьте количество POST в DevTools Network.
- Найдите тот же запрос в access log.
- Сопоставьте request_id в приложении и очереди.
- Посчитайте фактические вызовы метода создания сущности.
- Добавьте блокировку кнопки и серверную идемпотентность там, где найден повтор.
- Повторите сценарий с двойным кликом и искусственным сетевым таймаутом на тестовом контуре.
Три ошибки, которые только маскируют проблему
- Склеивать лиды после создания. Менеджер уже мог получить две задачи и два уведомления.
- Блокировать только кнопку. Это помогает против двойного клика, но не против retry на сервере.
- Искать только по телефону. Общий номер компании или повторное реальное обращение нельзя автоматически считать дублем.
- Логировать весь webhook URL. Так секрет интеграции попадает в журналы и системы мониторинга.
Чек-лист исправления
- Для submit есть один обработчик.
- Кнопка блокируется до завершения запроса.
- Каждое обращение получает request_id.
- Логи связываются по этому ID.
- Повторный payload не создаёт новую сущность.
- Retry имеет ограничение и понятную причину.
- Секреты и персональные данные не пишутся в открытый лог.
Что делать, если не помогло
Соберите один трассировочный пакет: время запроса, HAR без секретов, строки access log, request_id, номер попытки очереди и ID обеих CRM-записей. Если два POST уже видны в браузере, исправляйте frontend. Если POST один, а строк в access log две, проверяйте proxy и повтор клиента. Если до приложения дошёл один запрос, но методов создания два, причина внутри backend или очереди. Такой пакет обычно сужает проблему до одного слоя.
Когда нужен специалист
Подключайте разработчика, если у формы несколько обработчиков, есть очередь, webhook отвечает нестабильно или дубли появляются только под нагрузкой. CTR1 может проверить сайт перед запуском и разобрать, где теряются или дублируются заявки. Для соседних задач полезны разборы про резервную доставку заявок, выбор REST API или webhook и передачу UTM из формы в CRM.



