fix(tradein): avito sweep page-level retry — transient page error no longer aborts run #1755

Merged
lekss361 merged 1 commit from fix/avito-sweep-page-retry into main 2026-06-18 11:36:54 +00:00
Owner

Проблема (P2)

fetch_city_wide, fetch_by_rooms и _paginate_sweep (бэкает citywide + fetch_newbuildings) на transient browser/fetch-ошибке делали break → один сбой страницы N обрывал ВЕСЬ прогон (citywide) или категорию (byrooms), теряя хвост. Унаследовано от старого anchor-свипа; один apw-блип резал прогон.

Решение

Новый helper _fetch_serp_html_with_retry(url, page, *, max_retries=2) — до 3 попыток:

  • AvitoBlockedError/AvitoRateLimitedError → re-raise немедленно (hard-block, не retry);
  • generic Exception → warning + короткий backoff (max(2.0, min(request_delay_sec, 4.0))) + retry; после исчерпания → re-raise (внешний loop решает break);
  • None (non-200/конец пагинации) → возврат как есть, без retry.

fetch_city_wide/fetch_by_rooms/_paginate_sweep зовут helper вместо прямого _fetch_serp_html. Семантика внешнего break сохранена — но теперь срабатывает только на persistent failure (после retry), а не на первом transient-блипе. html is None → break без изменений.

Не тронуты fetch_all_secondary/_walk_price_range/_fetch_rooms_page_html (своя retry-логика из #1753).

Тесты

tests/scrapers/test_avito_sweep_retry.py (нов, 8): retry-recovers, re-raise после исчерпания, Blocked/RateLimited не-retry (call_count==1), None-no-retry, 2 integration fetch_city_wide (transient page выживает; persistent page=3 → graceful break, страницы 1-2 сохранены).

Full suite (prescribed deselects): 1970 passed, 1 skipped, 0 failed. Ruff clean.

## Проблема (P2) `fetch_city_wide`, `fetch_by_rooms` и `_paginate_sweep` (бэкает citywide + `fetch_newbuildings`) на transient browser/fetch-ошибке делали `break` → один сбой страницы N обрывал ВЕСЬ прогон (citywide) или категорию (byrooms), теряя хвост. Унаследовано от старого anchor-свипа; один apw-блип резал прогон. ## Решение Новый helper `_fetch_serp_html_with_retry(url, page, *, max_retries=2)` — до 3 попыток: - `AvitoBlockedError`/`AvitoRateLimitedError` → re-raise немедленно (hard-block, не retry); - generic `Exception` → warning + короткий backoff (`max(2.0, min(request_delay_sec, 4.0))`) + retry; после исчерпания → re-raise (внешний loop решает break); - `None` (non-200/конец пагинации) → возврат как есть, без retry. `fetch_city_wide`/`fetch_by_rooms`/`_paginate_sweep` зовут helper вместо прямого `_fetch_serp_html`. Семантика внешнего `break` сохранена — но теперь срабатывает только на **persistent** failure (после retry), а не на первом transient-блипе. `html is None → break` без изменений. Не тронуты `fetch_all_secondary`/`_walk_price_range`/`_fetch_rooms_page_html` (своя retry-логика из #1753). ## Тесты `tests/scrapers/test_avito_sweep_retry.py` (нов, 8): retry-recovers, re-raise после исчерпания, Blocked/RateLimited не-retry (call_count==1), None-no-retry, 2 integration `fetch_city_wide` (transient page выживает; persistent page=3 → graceful break, страницы 1-2 сохранены). Full suite (prescribed deselects): **1970 passed, 1 skipped, 0 failed**. Ruff clean.
lekss361 added 1 commit 2026-06-18 11:30:03 +00:00
fix(tradein): avito sweep page-level retry — transient page error no longer aborts run
All checks were successful
CI / changes (pull_request) Successful in 6s
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
6c132d7f0a
lekss361 added the
bug
scope/backend
scrapers
status/review
labels 2026-06-18 11:30:12 +00:00
bot-reviewer approved these changes 2026-06-18 11:36:48 +00:00
bot-reviewer left a comment
Collaborator

APPROVE — clean worktree head 6c132d7f.

P2 resilience fix, корректен:

  • _fetch_serp_html_with_retry: attempts=max_retries+1=3. AvitoBlockedError/AvitoRateLimitedError → re-raise НЕМЕДЛЕННО (не retry, hard-block сохранён). generic Exception → backoff(max(2.0,min(delay,4.0)))+retry, после исчерпания re-raise. None (non-200/конец пагинации) → возврат как есть, без retry — корректно (не ошибка).
  • Оба call-site (paginate-sweep url_builder loop + fetch_by_rooms) переключены на helper; внешний break-семантика сохранена (только persistent failure после retry, не первый transient блип). html is None → break без изменений.
  • fetch_all_secondary/_walk_price_range/_fetch_rooms_page_html (#1753) НЕ тронуты — своя retry-логика.

Тесты на чистом дереве: 1970 passed, 0 failed. Ruff clean. Merge (merge style).

✅ APPROVE — clean worktree head 6c132d7f. P2 resilience fix, корректен: - _fetch_serp_html_with_retry: attempts=max_retries+1=3. AvitoBlockedError/AvitoRateLimitedError → re-raise НЕМЕДЛЕННО (не retry, hard-block сохранён). generic Exception → backoff(max(2.0,min(delay,4.0)))+retry, после исчерпания re-raise. None (non-200/конец пагинации) → возврат как есть, без retry — корректно (не ошибка). - Оба call-site (paginate-sweep url_builder loop + fetch_by_rooms) переключены на helper; внешний break-семантика сохранена (только persistent failure после retry, не первый transient блип). `html is None → break` без изменений. - fetch_all_secondary/_walk_price_range/_fetch_rooms_page_html (#1753) НЕ тронуты — своя retry-логика. Тесты на чистом дереве: 1970 passed, 0 failed. Ruff clean. Merge (merge style).
lekss361 merged commit 0f975e8a53 into main 2026-06-18 11:36:54 +00:00
lekss361 deleted branch fix/avito-sweep-page-retry 2026-06-18 11:36:54 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: lekss361/gendesign#1755
No description provided.