fix(scraper-kit): containment до пробы у cian и yandex — резюм full-load не пере-пробивает готовые полосы #3362

Merged
bot-backend merged 2 commits from fix/3359-containment-cian-yandex into main 2026-09-05 19:19:32 +00:00
Collaborator

Closes #3359 (follow-up #3315/#3358). Гейт should_skip в движке был, предикат строил только avito.

Формат ключей — факт по коду

  • cian _paginate_leaf_bucket: f"{room_label}:{lo}:{_hi_repr}", открытый = open — идентичен avito → парсер по умолчанию.
  • yandex _combo_label: f"{rooms or 'any'}:{lo}-{hi}" — разделитель -, открытый потолок литерал None. Ключи не подогнаны (сломало бы старые чекпоинты): в done_range_skipper добавлены range_sep=":", open_token="open" (дефолты = прежнее поведение), yandex зовёт с range_sep="-", open_token="None". hi включительна у всех (движок делит [lo,mid]+[mid+1,hi]) → слияние смежных по +1 корректно.

Один леджер на два режима (предпосылка из ревью #3358)

  • cian: incremental-режима нет вовсе — неприменимо.
  • yandex: gate-combo ключи incremental'а несут префикс сегмента (secondary/2:4000000-4999999) — отсев key.startswith(f"{label}:") их не пропускает; плюс _pick_resume (params IS NOT DISTINCT FROM) — две независимые преграды, обе в докстринге, кейс на префиксный ключ в тесте.

Тесты

test_3359_{cian,yandex}_exhaustive_containment_skip.py: 155 passed, 1 skipped (-k bisect/pricing/parity/containment/serp; avito-тесты #3315 зелёные — параметризация обратно совместима). Фальсификация (откат yandex-хунка): полоса [4062500, 4124999] внутри зачтённой … сходил в сеть 1 раз, резюм готовой комнатности сделал 607 запрос(ов) вместо нуля — по значению; cian в том же прогоне зелёный.

Прод-приёмка

Первый живой резюм cian/yandex full-load: в логе skip probe … range already covered by done buckets (resume), просадка probe-запросов в начале прогона.

Closes #3359 (follow-up #3315/#3358). Гейт `should_skip` в движке был, предикат строил только avito. ## Формат ключей — факт по коду - **cian** `_paginate_leaf_bucket`: `f"{room_label}:{lo}:{_hi_repr}"`, открытый = `open` — идентичен avito → парсер по умолчанию. - **yandex** `_combo_label`: `f"{rooms or 'any'}:{lo}-{hi}"` — разделитель `-`, открытый потолок литерал `None`. Ключи не подогнаны (сломало бы старые чекпоинты): в `done_range_skipper` добавлены `range_sep=":"`, `open_token="open"` (дефолты = прежнее поведение), yandex зовёт с `range_sep="-", open_token="None"`. `hi` включительна у всех (движок делит `[lo,mid]+[mid+1,hi]`) → слияние смежных по `+1` корректно. ## Один леджер на два режима (предпосылка из ревью #3358) - cian: incremental-режима нет вовсе — неприменимо. - yandex: gate-combo ключи incremental'а несут префикс сегмента (`secondary/2:4000000-4999999`) — отсев `key.startswith(f"{label}:")` их не пропускает; плюс `_pick_resume` (`params IS NOT DISTINCT FROM`) — две независимые преграды, обе в докстринге, кейс на префиксный ключ в тесте. ## Тесты `test_3359_{cian,yandex}_exhaustive_containment_skip.py`: `155 passed, 1 skipped` (-k bisect/pricing/parity/containment/serp; avito-тесты #3315 зелёные — параметризация обратно совместима). Фальсификация (откат yandex-хунка): `полоса [4062500, 4124999] внутри зачтённой … сходил в сеть 1 раз`, `резюм готовой комнатности сделал 607 запрос(ов) вместо нуля` — по значению; cian в том же прогоне зелёный. ## Прод-приёмка Первый живой резюм cian/yandex full-load: в логе `skip probe … range already covered by done buckets (resume)`, просадка probe-запросов в начале прогона.
bot-backend added 1 commit 2026-09-05 18:57:47 +00:00
fix(cian,yandex): skip fully-covered price ranges before probing on resume
All checks were successful
CI Trade-In / changes (pull_request) Successful in 8s
CI / changes (pull_request) Successful in 9s
CI Trade-In / browser-tests (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Has been skipped
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
CI Trade-In / backend-tests (pull_request) Successful in 5m1s
35c7ea8492
Гейт should_skip живёт в общем движке (walk_price_range, #3315), но предикат
из done-леджера строил и передавал только avito. У cian и yandex та же
бисекция и тот же чекпоинт — на резюме дерево деления спускалось ВНУТРЬ
зачтённых полос живыми probe-запросами: ключи чекпоинта суть границы
ДИНАМИЧЕСКОЙ бисекции, при сдвиге рынка новый лист старому не равен даже
внутри собранной территории, поэтому сравнение строк ничего не ловит.

Формат ключей у провайдеров разный, и ключи не трогаем (иначе протухнут
живые чекпоинты): cian пишет room_label:lo:hi / :open — как avito, парсер
подходит без изменений; yandex пишет _combo_label «rooms:lo-hi» с «None»
вместо открытого потолка, поэтому в done_range_skipper параметризованы
range_sep и open_token (дефолты = прежнее поведение avito/cian).

Один леджер на два режима: у yandex incremental-ключи несут префикс
сегмента (secondary/2:…) и отсев по label их не пропускает, а смешение
режимов блокирует _pick_resume (params IS NOT DISTINCT FROM); у cian
incremental-режима нет вовсе. Записано в докстринге предиката.

Тесты по значению на обоих провайдерах: счётчик стоит на горлышке фетча
(_fetch_page_html / _fetch_page_json), резюм готовой комнатности = 0
запросов, частично покрытая полоса по-прежнему пробивается.

Closes #3359
Light1YT added 1 commit 2026-09-05 19:13:28 +00:00
fix(yandex): degraded-бакет не зачитывается как пройденный
All checks were successful
CI Trade-In / changes (pull_request) Successful in 8s
CI Trade-In / browser-tests (pull_request) Has been skipped
CI / changes (pull_request) Successful in 12s
CI Trade-In / frontend-checks (pull_request) Has been skipped
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
CI Trade-In / backend-tests (pull_request) Successful in 5m11s
4184f751bb
Ревью #3362: в _degraded (probe провалился → пагинация до пустоты, обрезаемая
max_pages_per_bucket) yandex звал on_bucket БЕЗ признака полноты, и ключ падал
в done-леджер наравне с честно добранным листом. До containment-гейта это был
точечный skip одного ключа; теперь ключ покрывает ИНТЕРВАЛ и сливается со
смежными — недобранная после отказа полоса больше никогда не переобходится.

Тот же путь, что у cian: третий позиционный аргумент complete, в чекпоинт
пишет только _mark_bucket(..., True); partial_buckets вынесен в счётчики
прогона (виден в heartbeat), лоты и cancel/shutdown-проверки не трогаем.

Плюс комментарий смежности в bisection.py приводил полуоткрытый пример, споря
с «hi ВКЛЮЧИТЕЛЬНА» в том же докстринге.
bot-backend merged commit 29c0ae006d into main 2026-09-05 19:19:32 +00:00
Author
Collaborator

Датированная приёмка выполнена (06.09 ~22:42 UTC, прод 68759927): первый реальный resume yandex full-load — run 6158 с resume_run_id=6157 (у 6157 done_buckets = ["studio:0-3999999", "studio:4000000-4999999"]). В логе backend ровно две строки:

yandex gate: skip probe rooms=studio [0, 3999999] — range already covered by done buckets (resume)
yandex gate: skip probe rooms=studio [4000000, 4999999] — range already covered by done buckets (resume)

ни одного gate-запроса по этим диапазонам; done_buckets 6158 = унаследованные 2 + новый studio:5000000-5999999; unique_fetched=149, partial_buckets=0, ошибок 0. Прогон снят coop-cancel через 100 с.

**Датированная приёмка выполнена (06.09 ~22:42 UTC, прод `68759927`):** первый реальный resume yandex full-load — run **6158** с `resume_run_id=6157` (у 6157 `done_buckets = ["studio:0-3999999", "studio:4000000-4999999"]`). В логе backend ровно две строки: ``` yandex gate: skip probe rooms=studio [0, 3999999] — range already covered by done buckets (resume) yandex gate: skip probe rooms=studio [4000000, 4999999] — range already covered by done buckets (resume) ``` ни одного gate-запроса по этим диапазонам; `done_buckets` 6158 = унаследованные 2 + новый `studio:5000000-5999999`; `unique_fetched=149`, `partial_buckets=0`, ошибок 0. Прогон снят coop-cancel через 100 с.
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#3362
No description provided.