The Catalog That Broke Over 48 Hours: An Incident Report, What We Found, What We Fixed
Author: WebGoodPeople
Один из клиентов в начале июня прислал сообщение в пятницу вечером: «С утра каталог отдаёт ошибки, конверсия упала в 3 раза, что делать». Сайт был не на нашем стеке — клиент обратился «отдельно, со стороны». У нас было 48 часов до понедельника, когда эта ситуация грозила стоить им кратно больше, чем аудит.
Это не чисто технический разбор — это хроника того, как проводится аварийный аудит, что типично находится и как это чинится. Все детали обобщены, клиент не называется.
Час 0: сигнал
19:40 пятницы, сообщение: «Ошибки на сайте, каталог не грузится у части пользователей. SEO-трафик падает. Не знаем что делать».
Первые три вопроса, которые я задаю:
- Что именно «не грузится» — страница отдаёт 500? Пустую страницу? Замедление?
- У всех пользователей или у части? Если у части — как определить «этих»?
- Когда это началось, и что было релизнуто в последние 48 часов?
Ответы: 500-ки на части страниц категорий, у всех пользователей этих категорий. Началось утром. Накануне был релиз — «обновили плагин для фильтров».
Час 1: доступ и первичный осмотр
Получаем доступ к серверу через SSH и логам через веб-интерфейс хостинга. Первые 15 минут — просто tail -f access-лога и error-лога.
tail -f /var/log/nginx/error.log
В error-логе видим повторяющуюся ошибку:
PHP Fatal error: Uncaught TypeError: Argument #1 ($values) must be of type array, null given, called in /bitrix/modules/iblock/classes/... at line 1247
Фатальная ошибка в plugin-коде фильтров. Код предполагает получить массив значений, получает null, падает.
Час 2: воспроизводим и локализуем
Открываем несколько страниц категорий в приватном режиме браузера. Часть — работают. Часть — 500-я.
Находим паттерн: падают те категории, где у свойства-фильтра нет значений вообще ни у одного товара. Плагин пытается строить фильтр, получает пустой массив, передаёт null в следующую функцию, та падает.
То есть релиз плагина накануне изменил поведение: раньше при отсутствии значений фильтр скрывался, теперь пытается строиться и падает на null.
Час 3: временный фикс
Правильный фикс — патч плагина. Но это риск: вендор может откатить изменения следующим апдейтом. Временный фикс — защита на уровне темплейта, которая проверяет, что массив значений не пустой, прежде чем отдавать плагину.
Добавляем условие:
if (!empty($filter_values) && is_array($filter_values)) {
// вызов плагина
}Деплой. Проверяем — 500-е исчезли на проблемных категориях.
Время от начала до фикса — 3 часа. Включая установление контакта, доступы, диагностику.
Час 4–24: что нашли во время «расширенного осмотра»
Это та часть, которая редко попадает в постмортемы, но часто самая ценная. Пока мы были на сервере, имело смысл посмотреть на общее состояние. Клиент согласился.
Что нашли за следующие 20 часов (никакой срочности, просто внимательное чтение):
1. API-лог отсутствует
В системе есть access.log от Nginx и error.log от PHP, но нет структурированного лога API-вызовов. Все «инциденты последнего квартала» разбирались через grep по access-логу — медленно и неточно.
Рекомендация: внедрить схему лога из 5 полей (см. наши статьи от апреля-мая). 1–2 дня работы, закрывает целый класс проблем.
2. Бэкапы есть, но не тестировались 14 месяцев
Бэкапы БД делаются каждую ночь. Rolling window — 14 дней. Но последняя тестовая восстановка из бэкапа делалась в апреле 2025 года. Это значит: формально бэкап есть, фактически мы не знаем, работает ли он.
Рекомендация: ежемесячная проверка restore в staging. 2 часа работы раз в месяц.
3. Права БД у веб-юзера: полный доступ
Веб-приложение ходит в MySQL с аккаунтом, у которого есть DROP, CREATE, ALTER. Это стандарт для Битрикс, но избыточно — для runtime ему нужны SELECT, INSERT, UPDATE, DELETE и в некоторых случаях CREATE TEMPORARY TABLE.
Рекомендация: отдельный юзер для админ-операций, отдельный — для рантайма. Снижение blast radius при компрометации.
4. Нет алертов на ошибки
PHP error.log пишется, но никто на него не смотрит в реальном времени. Инцидент начался утром, об этом узнали ближе к вечеру только потому, что клиент сам увидел провал конверсии.
Рекомендация: Loki / Fluent Bit → Grafana Alerting. Алерт на >10 PHP fatal errors в минуту — пейджер on-call. Установка — полдня.
5. Единая точка знаний (bus factor)
На собеседовании выяснилось, что весь стек «знает» один внешний фрилансер-разработчик, который уже 8 месяцев как не выходит на связь быстро. Когда он не отвечает, команда клиента не может деплоить даже мелкие правки. Что в данном случае и случилось — вендор плагина пушнул обновление, разработчик не на связи, клиент застрял.
Рекомендация: инвентаризация системы, документация ключевых процессов, второй инженер с прав admin. 2–3 недели работы.
6. Смешение staging и production
У клиента есть staging-среда, но некоторые тесты проходят напрямую на продакшене. «Это маленькая правка, зачем staging». Плагин фильтров тоже обновляли «маленько» — сразу в prod.
Рекомендация: жёсткое правило — ни одного деплоя минуя staging. Плюс автоматизация деплоя staging → production через CI (снижает frictions).
48 часов: итоговый отчёт клиенту
Документ на 9 страниц:
- Что произошло (30 минут чтения)
- Что мы сделали немедленно
- 6 находок, каждая с приоритетом и оценкой трудозатрат
- План на первые 30 дней (то, что чинится быстро)
- План на 90 дней (структурные изменения)
- Оценка «цены не-действия» (сколько стоит НЕ исправлять каждую проблему)
Самое важное для клиента в отчёте — пункт 6. Без него пункты 1–5 воспринимаются как «список желаний». С пунктом 6 — как «набор решений с конкретной окупаемостью».
Что из этого универсально
Любой Битрикс-проект, который живёт 3+ года, почти наверняка имеет:
- Отсутствие или слабость структурированных API-логов
- Нетестируемые бэкапы
- Избыточные права БД у рантайма
- Отсутствие алертов на ошибки приложения
- Высокий bus factor на legacy-компонентах
- Смешение staging/production в «маленьких правках»
Это не вина команды. Это накопленный долг, который никто не имел времени обслужить. Но каждая из этих проблем увеличивает время реакции на следующий инцидент — и стоимость простоя.
Если описанное выше звучит знакомо, у вас те же 48 часов в резерве.
48-часовой аудит без инцидента
Тот же по глубине отчёт можно получить до инцидента, а не после. Мы заходим в проект, смотрим 2 дня, возвращаем 9-страничный документ с 5–10 находками, приоритетом и ценой не-действия.
Стоимость — 0 ₽, это лид-магнит. Если после отчёта вы решите работать с нами по одной из находок — обсудим. Если нет — забираете отчёт и внедряете сами.
Read next
Articles on adjacent topics — from real projects.
Bitrix as a Headless API: What It Gives You and What It Does Not
What 1C-Bitrix provides out of the box as a headless backend, what requires custom development, and what is simply not worth the effort.
Blog · June 16, 2026Strangler Fig in Practice: A Category Page Migration, Commit by Commit
В прошлой статье (9 июня) разбирали strangler fig как стратегию: почему big-bang проваливается и как выглядит 6-этапный план в календаре. Эта статья — зум…
Blog · June 10, 20262-Week Pilot: What Actually Happens Inside
A transparent walkthrough of every phase in a headless pilot — what the client needs to prepare and what they get at the end.
Newsletter
Headless migrations & AI pilots, unpacked
Every 2 weeks — real cases, numbers and architecture decisions. No marketing noise.