CI выбрасывает историю по умолчанию. Для сборки это нормально, но для флаки-тестов — фатально: без истории нет диагностики. Одна append-only таблица и парсер для файла, который ваш CI уже пишет, — вот и весь дашборд. Он отвечает на три вопроса: какой тест чинить, день ли сегодня неудачный и не поменялась ли модель под нами.
Одна таблица — на уровне попыток
Соблазн хранить одну строку на тест за прогон — сопротивляйтесь. Флак от обычной ошибки отличается именно тем, что в одном прогоне тест и упал, и прошел. Если хранить только итоговый статус, этот сигнал исчезает до первого запроса.
Схема простая: каждая попытка — отдельная строка. Номер попытки, статус, время, коммит, ветка. Плюс четыре колонки, которые обычно добавляют через месяц мучений:
- model_served — модель из ответа, а не из конфига. Запрошенная модель статична и бесполезна, а реальная может меняться, когда алиас двигают. Без этой колонки вы не свяжете всплеск флаков с тихим обновлением модели.
- error_sig — нормализованная сигнатура ошибки. Считается при загрузке, а чинится потом за год истории — это боль.
- http_status — отделяет «провайдер вернул 429» от «упал ассерт». Это разные люди решают, а без колонки они выглядят одинаково.
- branch — флак на основной ветке и на фиче имеют разный масштаб, и в скоринге это учитывается.
Таблица должна быть append-only. Строка — исторический факт, и как только она станет изменяемой, кто-нибудь «поправит» пакет строк, и все трендовые линии тихо поедут. Ошибся парсер — удаляй строки по run_id и перечитывай из артефакта, он еще цел.
test_id обязан быть стабильным. Переименовали тест — история раскололась надвое. Если переименования происходят часто, заведите явный идентификатор, а не выводите из имени.
Загрузка из того, что CI уже производит
Не нужно инструментировать тестовый процесс. JUnit XML уже генерируют pytest (--junitxml), Vitest (--reporter=junit) и Playwright. Ретраи попадают в тот же testcase как flakyFailure или rerunFailure — ровно та структура, которая нужна таблице.
- Убедитесь, что каждый джоб пишет JUnit XML в фиксированное место, включая успешные прогоны. Они — знаменатель всех ставок.
- Добавьте всегда выполняемый шаг парсинга с метаданными CI: run_id, коммит, ветка. В GitHub Actions — if: always(), в GitLab — when: always. Иначе собираете данные только с зеленых прогонов, это бесполезно.
- Upsert с уникальным ключом (run_id, test_id, attempt), чтобы повторный запуск не дублировал строки.
- Подключите инструмент отображения: Grafana по Postgres, тетрадка с расписанием, статический HTML. Хранение — сложная часть, рендер — нет.
Три запроса, которые окупаются
Дашборд — не стена графиков. Три ответа закрывают почти все причины открыть его.
Первый — ранжированный список флаки-тестов за 30 дней. Для каждого теста считаем долю прогонов, где тест и падал, и проходил. Отсекаем те с менее чем 30 прогонами — это статистический мусор. Получаем бэклог «что чинить на этой неделе».
Второй — ежедневный флейк-рейт всего сьюта. Видно, сегодняшний день нетипичный или это новая норма. Дополнительно считаем distinct_causes: 40 падений с одной причиной — это инцидент; 4 падения с четырьмя причинами — просто неудачный день четырех несвязанных тестов.
Третий — флейк-рейт по каждой модели. Это звезда. Новое значение в model_served в тот же день, когда десяток тестов начал флакать, — готовый диагноз без чтения стектрейсов. Именно для этого стоит затевать всё. Работает, только если кто-то записывает реально обслужившую запрос модель, а не из конфига. Если сьюта переключается между провайдерами на лету, заполняйте колонку из ответа, который тест уже получил.
Хранение и стоимость
На уровне попыток строки копятся быстро: тесты × попытки × прогоны в день. Для пары сотен тестов в активном репозитории это сотни тысяч строк в месяц. Postgres такое переварит, но посчитайте заранее, чтоб не узнать на падении.
Сырые попытки храните ограниченное время — 90 дней хватает для всех запросов выше. Старые данные сверните в ежедневную сводку по тесту: отбросьте длительности и тексты ошибок, оставьте счетчики. Точный трейс флака от восьми месяцев назад не нужен никому, а счетчики питают трендовые линии.
Что выкинуть
Не добавляйте атрибуцию по разработчикам. Флак — это проблема теста или окружения, а не человека. Обвинениями флаки не чинятся. Лучше потратьте это время на то, чтобы третий запрос работал как надо.
Комментарии (0)
Войдите, чтобы комментировать.
Пока нет комментариев. Будьте первым.