diff --git a/scripts/parsers/openalex.py b/scripts/parsers/openalex.py index 76ba240..bd7c694 100644 --- a/scripts/parsers/openalex.py +++ b/scripts/parsers/openalex.py @@ -93,6 +93,8 @@ class OpenAlexParser(BaseParser): cursor = "*" per_page = min(200, limit) total_fetched = 0 + rate_limit_retries = 0 + MAX_RATE_LIMIT_RETRIES = 5 while total_fetched < limit: params: dict[str, Any] = { @@ -135,6 +137,7 @@ class OpenAlexParser(BaseParser): yield works total_fetched += len(works) + rate_limit_retries = 0 # успешный запрос — сбросить счётчик # Следующий курсор cursor = data.get("meta", {}).get("next_cursor") @@ -147,8 +150,19 @@ class OpenAlexParser(BaseParser): except httpx.HTTPStatusError as e: logger.error(f"OpenAlex HTTP ошибка: {e.response.status_code}") if e.response.status_code == 429: - logger.warning("Rate limit! Ожидаем 60 секунд...") - time.sleep(60) + rate_limit_retries += 1 + if rate_limit_retries > MAX_RATE_LIMIT_RETRIES: + logger.error( + f"OpenAlex: {MAX_RATE_LIMIT_RETRIES} подряд 429 — сдаюсь, " + f"забрано {total_fetched}/{limit}" + ) + break + # Экспоненциальный backoff: 60/120/240/480/960с — при нескольких + # параллельных воркерах плоское ожидание 60с не давало общему + # лимиту освободиться, каждый воркер продлевал блокировку сам. + wait = 60 * (2 ** (rate_limit_retries - 1)) + logger.warning(f"Rate limit! Попытка {rate_limit_retries}/{MAX_RATE_LIMIT_RETRIES}, ждём {wait}с...") + time.sleep(wait) continue break except Exception as e: