Почему для реализации retry лучше использовать while, а не for в Python?
Что проверяют
Слышите ли вы за формой цикла настоящий вопрос: чем ограничены повторы, числом попыток или временем. И понимаете ли, что повтор без разбора ошибки и без растущей паузы вреднее, чем его отсутствие.
Как отвечать
Честно сказать, что правила «только while» не существует. Когда попыток фиксированное число, for по диапазону читается чище, а конструкция for с else аккуратно ловит исчерпание попыток. while выигрывает, когда ограничение другое: общий бюджет времени, дедлайн, условие «пока сервис отвечает отказом по превышению лимита».
def call_with_retry(fn, attempts=5, base=0.2, cap=5.0):
for attempt in range(attempts):
try:
return fn()
except TransientError:
if attempt == attempts - 1:
raise
delay = min(cap, base * 2 ** attempt)
time.sleep(delay * (0.5 + random.random() / 2))Вариант с дедлайном действительно естественнее на while:
deadline = time.monotonic() + 30
while time.monotonic() < deadline:
...Дальше важнее самого цикла: повторять только временные сбои, то есть таймаут, обрыв соединения, ответ пятисотой серии, превышение лимита, и никогда ошибку валидации. Пауза растёт экспоненциально и разбавляется случайной добавкой. Повторяется только идемпотентная операция либо операция с ключом идемпотентности. Наружу отдаётся последнее исключение. В рабочем коде это берут готовым: tenacity, настройка повторов в адаптере requests.
Где спотыкаются
Гасят исключение и возвращают None после последней попытки. Вызывающий код принимает пустоту за валидный ответ и падает через три слоя выше, где причину уже не видно. Последнюю ошибку надо пробрасывать.
Повторяют всё подряд. Ответ о неверных данных, отсутствии ресурса или недостатке прав от повтора не изменится, зато нагрузка утроится. Ещё опаснее повторять неидемпотентную запись: вместо одного заказа появляется три.
Ставят фиксированную паузу в секунду без разброса и потолка. При массовом сбое все клиенты приходят одновременными волнами и не дают сервису подняться. Экспоненциальный рост со случайной добавкой разводит их во времени.