From 450940cafba447ddb595b073546b6b4d5fe8643d Mon Sep 17 00:00:00 2001 From: bot-backend Date: Tue, 15 Sep 2026 20:45:47 +0300 Subject: [PATCH] =?UTF-8?q?fix(scheduler):=20=D0=BE=D0=BF=D0=B5=D1=87?= =?UTF-8?q?=D0=B0=D1=82=D0=BA=D0=B0=20=D0=B2=20city=20=D1=80=D0=B0=D1=81?= =?UTF-8?q?=D0=BF=D0=B8=D1=81=D0=B0=D0=BD=D0=B8=D1=8F=20=D0=BF=D0=B0=D0=B4?= =?UTF-8?q?=D0=B0=D0=B5=D1=82,=20=D0=B0=20=D0=BD=D0=B5=20=D1=81=D0=BE?= =?UTF-8?q?=D0=B1=D0=B8=D1=80=D0=B0=D0=B5=D1=82=20=D0=95=D0=BA=D0=B0=D1=82?= =?UTF-8?q?=D0=B5=D1=80=D0=B8=D0=BD=D0=B1=D1=83=D1=80=D0=B3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CI ветки краснел на test_job_avito_city_sweep_unknown_city_falls_back_to_none: тест закреплял прежний контракт «неизвестный слаг → anchors=None», а реестр теперь бросает ValueError вместо молчаливого отката на ЕКБ. Правильное поведение — падать. anchors=None уводит свип на EKB_ANCHORS, то есть опечатка в default_params.city давала полноценный прогон по Екатеринбургу, проштампованный именем чужого города. Тик планировщика ValueError ловит (logger.exception в _run), цикл не умирает — крашится только этот прогон. Отсутствие ключа city по-прежнему даёт anchors=None и citywide-свип ЕКБ: это контракт старых расписаний, он не тронут. Комментарий на call-site приведён в соответствие — он всё ещё описывал возврат None. --- .../tests/test_scraper_kit_scheduler_parity.py | 17 ++++++++++------- .../src/scraper_kit/orchestration/scheduler.py | 6 ++++-- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/tradein-mvp/backend/tests/test_scraper_kit_scheduler_parity.py b/tradein-mvp/backend/tests/test_scraper_kit_scheduler_parity.py index 1480dfcc..b657bf60 100644 --- a/tradein-mvp/backend/tests/test_scraper_kit_scheduler_parity.py +++ b/tradein-mvp/backend/tests/test_scraper_kit_scheduler_parity.py @@ -550,17 +550,20 @@ async def test_job_avito_city_sweep_without_city_param_falls_back_to_none() -> N assert kwargs["anchors"] is None -async def test_job_avito_city_sweep_unknown_city_falls_back_to_none() -> None: - """Неизвестный city slug (typo/будущий город без CITY_ANCHORS-записи) → anchors=None, +async def test_job_avito_city_sweep_unknown_city_raises_instead_of_sweeping() -> None: + """Неизвестный city slug (опечатка в расписании) обязан упасть, а не собрать ЕКБ. - НЕ падает с KeyError. + Раньше `get_city_anchors` отдавал None, и свип уходил на EKB_ANCHORS: опечатка в + `default_params.city` тихо давала прогон по Екатеринбургу, проштампованный чужим + городом. Теперь реестр падает с ValueError; прогон крашится, а тик планировщика + это ловит (`logger.exception` в `_run`, scheduler.py) — цикл не умирает, но и + мусора в корпус не попадает. """ with patch.object(kit_sched, "run_avito_city_sweep", AsyncMock()) as mock_run: - await _job_avito_city_sweep(MagicMock(), 1, {"city": "nonexistent_town"}, _oblast_ctx()) + with pytest.raises(ValueError, match="nonexistent_town"): + await _job_avito_city_sweep(MagicMock(), 1, {"city": "nonexistent_town"}, _oblast_ctx()) - mock_run.assert_awaited_once() - _args, kwargs = mock_run.call_args - assert kwargs["anchors"] is None + mock_run.assert_not_awaited() # ── #2616: _job_avito_full_load(_exhaustive) прокидывает ctx.proxy_provider ────── diff --git a/tradein-mvp/packages/scraper-kit/src/scraper_kit/orchestration/scheduler.py b/tradein-mvp/packages/scraper-kit/src/scraper_kit/orchestration/scheduler.py index 4e6e1a14..2611fa02 100644 --- a/tradein-mvp/packages/scraper-kit/src/scraper_kit/orchestration/scheduler.py +++ b/tradein-mvp/packages/scraper-kit/src/scraper_kit/orchestration/scheduler.py @@ -1058,8 +1058,10 @@ async def _job_avito_city_sweep( db: Session, run_id: int, params: dict[str, Any], ctx: SchedulerContext ) -> None: # #B1 oblast rollout: default_params["city"] (slug, e.g. "nizhniy_tagil") → anchors - # города вместо EKB_ANCHORS. Отсутствует/неизвестен → get_city_anchors вернёт None → - # run_avito_city_sweep сам падает на EKB_ANCHORS (прежнее поведение без city). + # города вместо EKB_ANCHORS. Ключа нет вовсе → anchors=None → citywide-свип ЕКБ + # (прежнее поведение расписаний без city). Ключ ЕСТЬ, но слаг неизвестен → + # get_city_anchors падает с ValueError: опечатка в расписании раньше тихо давала + # прогон по Екатеринбургу под именем чужого города. city = params.get("city") anchors = get_city_anchors(city) if city else None await run_avito_city_sweep(