Merge pull request 'refactor(tradein/tasks): avito_detail_backfill build_warmed_session на kit + config= (#2397 Part D1, #2330)' (#2410) from refactor/tradein-partD1-avito-detail-backfill-kit into main
Some checks failed
Deploy Trade-In / build-backend (push) Blocked by required conditions
Deploy Trade-In / deploy (push) Blocked by required conditions
Deploy Trade-In / changes (push) Successful in 10s
Deploy Trade-In / build-frontend (push) Has been skipped
Deploy Trade-In / build-browser (push) Has been skipped
Deploy Trade-In / test (push) Has been cancelled
Some checks failed
Deploy Trade-In / build-backend (push) Blocked by required conditions
Deploy Trade-In / deploy (push) Blocked by required conditions
Deploy Trade-In / changes (push) Successful in 10s
Deploy Trade-In / build-frontend (push) Has been skipped
Deploy Trade-In / build-browser (push) Has been skipped
Deploy Trade-In / test (push) Has been cancelled
This commit is contained in:
commit
c8343c8f3d
2 changed files with 61 additions and 16 deletions
|
|
@ -39,6 +39,8 @@ from scraper_kit.browser_fetcher import BrowserFetcher
|
|||
# зависимость от scrape_pipeline.py перед его удалением.
|
||||
from scraper_kit.providers._base import DOCUMENT_HEADERS, http_proxies
|
||||
from scraper_kit.providers.avito.detail import (
|
||||
_AVITO_WARM_SEARCH_URL,
|
||||
build_warmed_session,
|
||||
fetch_detail,
|
||||
research_in_session,
|
||||
save_detail_enrichment,
|
||||
|
|
@ -52,20 +54,14 @@ from app.core.shutdown import shutdown_requested
|
|||
from app.services import scrape_runs as runs_mod
|
||||
from app.services.scraper_adapters import RealScraperConfig
|
||||
|
||||
# _AVITO_WARM_SEARCH_URL/build_warmed_session остаются legacy (#2310): kit's
|
||||
# scraper_kit.providers.avito.detail.build_warmed_session() строит сессию через
|
||||
# _build_detail_session() БЕЗ config-параметра (сигнатура вообще не принимает
|
||||
# ScraperConfig — в отличие от fetch_detail, здесь нет caller-side способа
|
||||
# прокинуть прокси). Мигрировав этот импорт, warm-batch curl-путь (use_curl=True,
|
||||
# ДЕФОЛТ прод-режима, avito_detail_backfill_use_curl=True) молча перестал бы
|
||||
# использовать settings.scraper_proxy_url (sticky МГТС-прокси) — прямое
|
||||
# datacenter-подключение вместо backconnect. Тот же класс бага, что #2322
|
||||
# (недостающая инъекция конфига в scraper_kit provider-функции), но другая
|
||||
# функция — заведён как отдельный follow-up, НЕ #2322. См. отчёт issue #2310.
|
||||
from app.services.scrapers.avito_detail import (
|
||||
_AVITO_WARM_SEARCH_URL,
|
||||
build_warmed_session,
|
||||
)
|
||||
# #2397 Part D1 (#2330 закрыт): _AVITO_WARM_SEARCH_URL/build_warmed_session больше
|
||||
# НЕ legacy — kit's scraper_kit.providers.avito.detail.build_warmed_session() теперь
|
||||
# принимает config: ScraperConfig | None (Strangler-инъекция #2330) и пробрасывает
|
||||
# его в _build_detail_session() для settings.scraper_proxy_url (sticky МГТС-прокси),
|
||||
# зеркаля fetch_detail. Оба call site'а ниже передают config=RealScraperConfig() —
|
||||
# без него warm-batch curl-путь (use_curl=True, ДЕФОЛТ прод-режима,
|
||||
# avito_detail_backfill_use_curl=True) молча терял бы backconnect (прямое
|
||||
# datacenter-подключение вместо sticky-прокси), тот же класс бага что #2322/#2310.
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
|
@ -174,7 +170,10 @@ async def run_avito_detail_backfill(
|
|||
# фикс. exit-IP, per-connection ротации нет (rebuild != новый IP); on-block —
|
||||
# cooldown + in-session re-search, не дискард сессии.
|
||||
own_session = True
|
||||
session = await build_warmed_session()
|
||||
# config= обязателен: #2397 Part D1 — kit build_warmed_session() без него
|
||||
# молча теряет settings.scraper_proxy_url (sticky МГТС-прокси), см. модуль-
|
||||
# ный комментарий у импорта выше.
|
||||
session = await build_warmed_session(config=RealScraperConfig())
|
||||
elif not use_curl:
|
||||
# curl_cffi legacy path (scraper_fetch_mode="curl_cffi", use_curl=False):
|
||||
# строим shared сессию через auv, как делает run_avito_city_sweep (kit).
|
||||
|
|
@ -296,8 +295,12 @@ async def run_avito_detail_backfill(
|
|||
# #1950: bound сетевой re-warm; строим НОВУЮ сессию до close старой — на
|
||||
# timeout/fail сохраняем текущую рабочую сессию (graceful degrade).
|
||||
try:
|
||||
# config= обязателен здесь тоже (тот же footgun, что и в setup-
|
||||
# вызове build_warmed_session выше) -- иначе периодический re-warm
|
||||
# молча пересобрал бы сессию БЕЗ sticky-прокси после первого раза.
|
||||
new_session = await asyncio.wait_for(
|
||||
build_warmed_session(), timeout=warm_timeout_s
|
||||
build_warmed_session(config=RealScraperConfig()),
|
||||
timeout=warm_timeout_s,
|
||||
)
|
||||
try:
|
||||
await session.close()
|
||||
|
|
|
|||
|
|
@ -148,6 +148,48 @@ async def test_backfill_processes_snapshot_to_completion() -> None:
|
|||
assert isinstance(mock_scraper_cls.call_args.args[0], RealScraperConfig)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_backfill_build_warmed_session_receives_config() -> None:
|
||||
"""#2397 Part D1 / #2330 regression guard: kit's build_warmed_session() now accepts
|
||||
config=ScraperConfig and silently drops settings.scraper_proxy_url (sticky МГТС-прокси)
|
||||
-- NO crash, just a proxy-less session -- unless config=RealScraperConfig() is passed
|
||||
at the call site. use_curl=True is the prod-default path (avito_detail_backfill_use_curl),
|
||||
so this is the setup-time build_warmed_session() call (~line 177). assert_awaited_once()
|
||||
alone wouldn't catch someone dropping the kwarg later (mirrors the fetch_detail config=
|
||||
guard above, lines 141-148)."""
|
||||
from app.services.scraper_adapters import RealScraperConfig
|
||||
|
||||
snapshot = _make_snapshot(1)
|
||||
db = _mock_db(snapshot)
|
||||
runs = MagicMock()
|
||||
mock_enrichment = MagicMock()
|
||||
mock_fetch = AsyncMock(return_value=mock_enrichment)
|
||||
mock_save = MagicMock(return_value=True)
|
||||
fake_settings = MagicMock(
|
||||
scraper_fetch_mode="cffi",
|
||||
avito_detail_backfill_use_curl=True,
|
||||
)
|
||||
with (
|
||||
patch(_SETTINGS, fake_settings),
|
||||
patch(_SCRAPER),
|
||||
patch(_RUNS, runs),
|
||||
patch(_FETCH, mock_fetch),
|
||||
patch(_SAVE, mock_save),
|
||||
patch(_SLEEP, new_callable=AsyncMock),
|
||||
patch(_BUILD_WARM, AsyncMock(return_value=AsyncMock())) as mock_build,
|
||||
):
|
||||
result = await run_avito_detail_backfill(
|
||||
db, run_id=15, params={"batch_size": 10, "budget_sec": 3600}
|
||||
)
|
||||
|
||||
assert result.enriched == 1
|
||||
mock_build.assert_awaited_once()
|
||||
_, build_call_kwargs = mock_build.call_args
|
||||
assert isinstance(build_call_kwargs.get("config"), RealScraperConfig)
|
||||
runs.mark_done.assert_called_once()
|
||||
runs.mark_failed.assert_not_called()
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_backfill_blocked_abort_after_max_consecutive() -> None:
|
||||
"""5 consecutive AvitoBlockedError -> abort, mark_done (NOT mark_failed).
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue