Короткий ответ
Нужно сначала разделить причины — сетевые ограничения CI-окружения (другой регион, прокси, фаервол), ограниченные ресурсы раннера или реальная нестабильность самого внешнего API — собрав логи времени ответа и кодов ошибок, а затем добавить явный таймаут, ретраи с экспоненциальной задержкой и чёткое логирование вместо "тихого" падения теста.
Как это работает подробнее
CI-раннеры часто находятся в другом сетевом окружении (другой дата-центр/регион, общие с другими джобами ресурсы, возможные ограничения на исходящие соединения), из-за чего задержки и процент ошибок выше, чем на машине разработчика; "флаки" тест обычно означает, что система балансирует на грани таймаута, а не что тест написан неверно сам по себе.
Пример кода
example-479.py
import time
import random
import requests
def call_with_retry(url, max_attempts=4, base_delay=0.5, timeout=3):
last_exc = None
for attempt in range(1, max_attempts + 1):
try:
response = requests.get(url, timeout=timeout)
response.raise_for_status()
return response.json()
except requests.exceptions.RequestException as exc:
last_exc = exc
delay = base_delay * (2 ** (attempt - 1)) + random.uniform(0, 0.2)
print(f"Попытка {attempt} не удалась: {exc}, повтор через {delay:.2f}с")
time.sleep(delay)
raise last_excЧто использовать на практике
- Рекомендация. диагностику начинают со сбора данных — логировать время запроса, код ответа и количество попыток при каждом падении в CI, запустить тест несколько десятков раз подряд в CI, чтобы оценить частоту сбоя. После этого добавляют
timeout, retry с экспоненциальной задержкой и джиттером на стороне клиента, ограничивая общее число попыток, и отдельно решают, стоит ли тест вообще гонять против реального внешнего API или заменить его моком/контрактным тестом.
Подводные камни
- Ошибка. просто увеличивать таймаут "на глаз" без понимания причины; добавлять
@retryбез ограничения суммарного времени ожидания, из-за чего один флаки-тест начинает держать CI-джобу по много минут; маскировать проблему черезcontinue-on-error, теряя сигнал о реальной деградации внешнего сервиса.