Интеграционный job зелёный локально, но флакает в CI примерно в 1 прогоне из 5 без изменений кода. Найдите и устраните причину.
Эта задача поднимает API рядом с сервисом базы данных, затем гоняет интеграционный набор. Локально и на большинстве прогонов CI она зелёная, но примерно один прогон из пяти падает с ошибками connection-refused из тестов — тот же коммит, без изменений кода. Найдите корневую причину флакования в конфиге и исправьте её.
integration-test:
stage: test
services:
- name: postgres:16
alias: db
script:
- ./start-app.sh & # поднимает API, коннектится к db
- sleep 3 # даём время подняться
- pytest tests/integration/
Объясните, почему флакает, и дайте фикс.
sleep 3 — гонка: под нагрузкой CI приложение или база не всегда готовы за три секунды, поэтому часть прогонов тестит рано и падает с connection-refused. Замените его опросом готовности health-эндпоинта с таймаутом перед pytest. Ждите условие, а не часы.
- ✗Лечить гонку удлинением sleep вместо ожидания готовности
- ✗Прятать флакование сплошным retry задачи вместо корневой причины
- ✗Винить железо CI вместо допущения о таймингах в конфиге
- →Как выглядел бы опрос готовности с таймаутом в скрипте?
- →Когда ограниченный retry задачи уместен, а когда прячет реальные баги?
Решение
Причина
sleep 3 — это неявная гонка. Он допускает, что приложение и база поднимутся ровно за три секунды. На локальной машине это часто так, но под нагрузкой раннера CI старт иногда занимает дольше — тогда pytest стартует раньше готовности и ловит connection-refused. Отсюда недетерминированное «1 из 5».
Фикс — ждать условие, а не время
integration-test:
stage: test
services:
- name: postgres:16
alias: db
script:
- ./start-app.sh &
- |
for i in $(seq 1 30); do
curl -fsS http://localhost:8080/health && break
sleep 1
done
- curl -fsS http://localhost:8080/health # финальная проверка, иначе job падает
- pytest tests/integration/
Опрос health-эндпоинта в цикле с повторами и таймаутом убирает зависимость от часов: тесты стартуют ровно тогда, когда сервис реально готов. Отдельно — вынесите общее изменяемое состояние и уберите зависимость тестов от порядка. Сплошной retry прячет корневую причину, а не устраняет её.