fix(tradein/proxy): проба Домклика спрашивает защищённый путь, а не robots.txt (#2855) #2856

Merged
bot-backend merged 1 commit from fix/2855-probe-protected-path into main 2026-08-13 06:02:38 +00:00
Collaborator

Что чинится

Проба узла и работа делили транспорт и хост, но не ресурс:

проба:  GET https://bff-search-web.domclick.ru/robots.txt
работа: GET https://bff-search-web.domclick.ru/api/offers/v1?…

QRATOR закрывает /api/offers/* и не трогает robots.txt, поэтому проба отвечала 200 «пара здорова» ровно тогда, когда свип с того же узла получал блок-страницу.

Числа с прода 13.08

проверок пар узел×площадка за сутки 64
из них забанено (все площадки) 5
блокировок свипа Домклика каждые сутки без исключения
04:30:57  proxy_healthcheck: pair_checked=4, pair_banned=0  → все пары здоровы
05:02:12  domclick-sweep: QRATOR block during rooms='1'
05:02:12  proxy id=11 BANNED by source=domclick

Через полчаса проба снова скажет «здоров», и цикл повторится. Зелёный ответ здесь не бесполезен, а вреден — он читается как разрешение выдать узел.

Что сделано

Адрес пробы Домклика — count-эндпоинт /api/offers/count/v1: та же защищённая семья путей, что у работы, но ответ — одно число, без пагинации и без выдачи. Нагрузка на площадку остаётся минимальной, и это тот же довод, по которому здесь используется /fetch, а не /fetch-json (последний делает переход на главную).

Признак «ресурс отдан» стал зависеть от площадки: User-agent у robots.txt-источников, snippetsCount у Домклика. Вынесен отдельной картой, а не условием в теле, чтобы добавление площадки с боевым путём было одной строкой.

Параметры запроса продублированы из providers/domclick/serp.py::_build_count_url намеренно: импорт провайдера в browser_fetcher дал бы цикл (провайдеры уже импортируют его).

Знание было в коде на шаг от вывода

Пункт 4 шапки test_2800_per_source_probe.py уже гласил: «robots.txt площадка отдаёт и забаненному IP». Следствие обработали — проба не гасит боевой бан. Причину, что тогда она и о защищённом пути ничего не говорит, не заметили.

Красный прогон

Тем же файлом теста на origin/main (детач-worktree): 4 failed, 14 passed. На ветке: 18 passed.

Падают: адрес Домклика (/api/offers/count/v1 против robots.txt), текст отказа (теперь называет конкретный маркер), и обе половины нового теста.

Двусторонность держится внутри ветки: параметризация даёт случай блок-страницы (ok=False) и случай живого ответа (ok=True) — реализация «маркер не найден никогда» провалила бы вторую. На origin/main вторая половина тоже красная, но по другой причине — там ok выходит True, и падает проверка адреса; в комментарии теста это записано явно, чтобы не выдавать её за двусторонний контроль на обеих сторонах.

Смежные наборы: test_2723_browser_probe + test_proxy_pool + test_kit_browser_fetcher_proxy_pool85 passed.

Что это НЕ чинит

Сбор не воскреснет: правка делает отказ видимым, а не снимает его. Пул перестанет выдавать Домклику узел, про который уже известно, что площадка его отбивает.

Риск назвать числом: узлов четыре. Если площадка отбивает на всех, честная проба забанит все четыре пары, и Домклик останется без узлов до истечения шестичасовых банов. Это может оказаться хуже нынешнего, где узел выдаётся и часть лотов всё же собирается (79 за прогон 13.08). Проверять после деплоя: число забаненных пар узел×domclick за сутки и выработка свипа — если выработка упала до нуля, размен не оправдался.

Refs #2855, #2657, #2854

## Что чинится Проба узла и работа делили транспорт и **хост**, но не **ресурс**: ``` проба: GET https://bff-search-web.domclick.ru/robots.txt работа: GET https://bff-search-web.domclick.ru/api/offers/v1?… ``` QRATOR закрывает `/api/offers/*` и не трогает `robots.txt`, поэтому проба отвечала 200 «пара здорова» ровно тогда, когда свип с того же узла получал блок-страницу. ## Числа с прода 13.08 | | | |---|---:| | проверок пар узел×площадка за сутки | 64 | | из них забанено (**все** площадки) | 5 | | блокировок свипа Домклика | **каждые сутки без исключения** | ``` 04:30:57 proxy_healthcheck: pair_checked=4, pair_banned=0 → все пары здоровы 05:02:12 domclick-sweep: QRATOR block during rooms='1' 05:02:12 proxy id=11 BANNED by source=domclick ``` Через полчаса проба снова скажет «здоров», и цикл повторится. Зелёный ответ здесь не бесполезен, а **вреден** — он читается как разрешение выдать узел. ## Что сделано Адрес пробы Домклика — **count-эндпоинт** `/api/offers/count/v1`: та же защищённая семья путей, что у работы, но ответ — одно число, без пагинации и без выдачи. Нагрузка на площадку остаётся минимальной, и это тот же довод, по которому здесь используется `/fetch`, а не `/fetch-json` (последний делает переход на главную). Признак «ресурс отдан» стал зависеть от площадки: `User-agent` у robots.txt-источников, `snippetsCount` у Домклика. Вынесен отдельной картой, а не условием в теле, чтобы добавление площадки с боевым путём было одной строкой. Параметры запроса продублированы из `providers/domclick/serp.py::_build_count_url` намеренно: импорт провайдера в `browser_fetcher` дал бы цикл (провайдеры уже импортируют его). ## Знание было в коде на шаг от вывода Пункт 4 шапки `test_2800_per_source_probe.py` уже гласил: «**robots.txt площадка отдаёт и забаненному IP**». Следствие обработали — проба не гасит боевой бан. Причину, что тогда она и о защищённом пути ничего не говорит, не заметили. ## Красный прогон Тем же файлом теста на `origin/main` (детач-worktree): **4 failed, 14 passed**. На ветке: **18 passed**. Падают: адрес Домклика (`/api/offers/count/v1` против robots.txt), текст отказа (теперь называет конкретный маркер), и обе половины нового теста. **Двусторонность** держится внутри ветки: параметризация даёт случай блок-страницы (`ok=False`) и случай живого ответа (`ok=True`) — реализация «маркер не найден никогда» провалила бы вторую. На `origin/main` вторая половина тоже красная, но по другой причине — там `ok` выходит True, и падает проверка адреса; в комментарии теста это записано явно, чтобы не выдавать её за двусторонний контроль на обеих сторонах. Смежные наборы: `test_2723_browser_probe` + `test_proxy_pool` + `test_kit_browser_fetcher_proxy_pool` — **85 passed**. ## Что это НЕ чинит Сбор не воскреснет: правка делает отказ **видимым**, а не снимает его. Пул перестанет выдавать Домклику узел, про который уже известно, что площадка его отбивает. **Риск назвать числом:** узлов четыре. Если площадка отбивает на всех, честная проба забанит все четыре пары, и Домклик останется без узлов до истечения шестичасовых банов. Это может оказаться хуже нынешнего, где узел выдаётся и часть лотов всё же собирается (79 за прогон 13.08). Проверять после деплоя: число забаненных пар `узел×domclick` за сутки и выработка свипа — если выработка упала до нуля, размен не оправдался. Refs #2855, #2657, #2854
bot-backend added 1 commit 2026-08-13 05:53:03 +00:00
fix(tradein/proxy): проба Домклика спрашивает защищённый путь, а не robots.txt
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 4m12s
f967533272
Проба и работа делили транспорт и хост, но не РЕСУРС: проба брала
bff-search-web.domclick.ru/robots.txt, работа — /api/offers/v1. QRATOR закрывает
API и не трогает robots.txt, поэтому проба отвечала 200 «пара здорова» ровно
тогда, когда свип с того же узла получал блок-страницу.

Прод 13.08: за сутки 64 проверки пар и 5 банов на ВСЕ четыре площадки, при том
что свип Домклика блокируется каждые сутки. В 04:30 healthcheck пишет
pair_banned=0, в 05:02 свип — QRATOR block и узел 11 в бан на шесть часов.
Зелёный ответ здесь не бесполезен, а вреден: читается как разрешение выдать узел.

Адрес пробы — count-эндпоинт (/api/offers/count/v1): та же защищённая семья
путей, что у работы, но ответ одно число, без пагинации и выдачи. Нагрузка на
площадку минимальна — тот же довод, по которому здесь /fetch, а не /fetch-json.

Признак «ресурс отдан» стал зависеть от площадки: 'User-agent' у
robots.txt-источников, 'snippetsCount' у Домклика. Отдельной картой, а не
условием в теле, чтобы добавление площадки было одной строкой.

Знание было в коде на шаг от вывода: п.4 шапки test_2800 уже гласил
«robots.txt площадка отдаёт и забаненному IP». Следствие обработали (проба не
гасит боевой бан), причину — нет.

Красный прогон: 4 падения на origin/main тем же файлом теста, 18 зелёных на
ветке. Смежные — 85 passed.

Refs #2855, #2657
Author
Collaborator

Уточнение риска — он меньше, чем я написал выше, и вот почему

В теле PR я назвал риск: честная проба забанит все четыре пары, Домклик останется без узлов, и станет хуже нынешних 79 лотов. Додумал до конца — так не выйдет, и довод стоит записать до мержа.

Блок возникает ВО ВРЕМЯ прогона, а не до него. Свип успевает собрать 79-372 лота за 111-332 секунды, и только потом получает блок-страницу. Значит на момент выдачи узел не был отбит — иначе первая же страница вернула бы блок и лотов было бы ноль.

Отсюда поведение новой пробы:

состояние узла на момент пробы что вернёт проба что было бы без правки
свежий, не отбитый 200 + snippetsCount → годен годен (совпадает)
уже отбит (в шестичасовом бане) блок → пара забанена «годен» → узел выдан → прогон соберёт 0

То есть правка отказывает ровно в тех случаях, где прогон и так дал бы ноль, и не отказывает там, где он собрал бы свои 79. Потери выработки быть не должно.

Остаточная неопределённость, которую не снимаю: это рассуждение, а не замер. Возможен режим, где площадка держит узел отбитым дольше нашего шестичасового бана, и тогда проба будет честно отказывать чаще, чем сегодня выдаётся. Поэтому критерий приёмки остаётся прежним и проверяется числом.

Критерий приёмки, записанный до факта

Первый свип Домклика после деплоя (расписание — около 05:00 UTC):

  • выработка не упала: lots_fetched сопоставим с 58-79 последних суток. Ноль означает, что размен не оправдался и правку надо откатывать, а не объяснять;
  • проба стала различать: за сутки после деплоя число забаненных пар узел×domclick больше нуля. Если по-прежнему ноль при ежедневном блоке свипа — правка не сработала, и snippetsCount не тот признак.

Оба числа снимаются одним запросом к scrape_runs и scrape_proxy_source_bans.

## Уточнение риска — он меньше, чем я написал выше, и вот почему В теле PR я назвал риск: честная проба забанит все четыре пары, Домклик останется без узлов, и станет хуже нынешних 79 лотов. Додумал до конца — так не выйдет, и довод стоит записать **до** мержа. **Блок возникает ВО ВРЕМЯ прогона, а не до него.** Свип успевает собрать 79-372 лота за 111-332 секунды, и только потом получает блок-страницу. Значит на момент выдачи узел не был отбит — иначе первая же страница вернула бы блок и лотов было бы ноль. Отсюда поведение новой пробы: | состояние узла на момент пробы | что вернёт проба | что было бы без правки | |---|---|---| | свежий, не отбитый | **200 + `snippetsCount` → годен** | годен (совпадает) | | уже отбит (в шестичасовом бане) | **блок → пара забанена** | «годен» → узел выдан → прогон соберёт 0 | То есть правка отказывает ровно в тех случаях, где прогон и так дал бы ноль, и **не** отказывает там, где он собрал бы свои 79. Потери выработки быть не должно. **Остаточная неопределённость, которую не снимаю:** это рассуждение, а не замер. Возможен режим, где площадка держит узел отбитым дольше нашего шестичасового бана, и тогда проба будет честно отказывать чаще, чем сегодня выдаётся. Поэтому критерий приёмки остаётся прежним и проверяется числом. ## Критерий приёмки, записанный до факта Первый свип Домклика после деплоя (расписание — около 05:00 UTC): - **выработка не упала**: `lots_fetched` сопоставим с 58-79 последних суток. Ноль означает, что размен не оправдался и правку надо откатывать, а не объяснять; - **проба стала различать**: за сутки после деплоя число забаненных пар `узел×domclick` больше нуля. Если по-прежнему ноль при ежедневном блоке свипа — правка не сработала, и `snippetsCount` не тот признак. Оба числа снимаются одним запросом к `scrape_runs` и `scrape_proxy_source_bans`.
bot-backend merged commit 06c322c167 into main 2026-08-13 06:02:38 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
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#2856
No description provided.