Commit graph

2 commits

Author SHA1 Message Date
bot-backend
09bdd7888b fix(tradein/domclick): перезапуск браузера на карточку уничтожал пропуск QRATOR (#3212)
All checks were successful
CI Trade-In / changes (pull_request) Successful in 10s
CI / changes (pull_request) Successful in 19s
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 / browser-tests (pull_request) Successful in 1m10s
CI Trade-In / backend-tests (pull_request) Successful in 5m23s
ДомКлик закрыт QRATOR с proof-of-work: первый запрос отдаёт 401 и заглушку с
задачей, браузер её решает, дёргает /__qrator/validate и получает пропуск в куках
(qrator_jsid2 + qrator_jsr). Пропуск живёт в cookie jar, то есть в browser
context'е — а прод брал каждую карточку в новом контексте, выбрасывая его.
Повторная валидация с того же IP получала 403 и страницу bot-mitigation.

Замер (прод, прод-прокси, по 6 карточек):
  общий контекст, одна вкладка       6/6, validate не вызывался ни разу
  общий контекст, вкладка на карточку 6/6, validate не вызывался ни разу
  новый контекст на карточку (= прод) 1/6, validate = [304, 403] на каждой
  боевой путь /fetch с reuse_context  6/6 при 0 перезапусков и 1 контексте

Что правится:
  * снят код-дефолт domclick=1 из #3205: перезапуск процесса гарантированно
    уничтожает контекст, то есть лечил симптом, который сам же и создавал.
    Ручка per-provider и domclick как отдельный провайдер остаются;
  * сброс контекста в бэкфилле был на КАЖДЫЙ блок — стал один раз за прогон.
    Это и объясняет провал #3193: сброс выбрасывал пропуск, следующий фетч
    блокировался гарантированно, что снова вызывало сброс. Приёмка тогда дала
    ровно 1 успех из 10;
  * снята неверная формулировка «отказ, а не челлендж» из #3204/#3205 —
    26 624 байта это РЕЗУЛЬТАТ проваленного PoW, а не статика вместо него.
    Ошибка вышла из метода: HTML читали на 4.5-й секунде и не смотрели в сеть.

Замер 6/6, которым обосновывали #3205, был испорчен: в логах сайдкара после
каждой страницы стоит «recycle threshold (1) достигнут, перезапуск браузера».

Тесты: два кодировали domclick=1 — переписаны через подставной словарь, чтобы
уровень «код-дефолт поставщика» продолжал проверяться, а не исчез вместе с
записью. Тест сброса требует ровно одну попытку за прогон.
159 passed (сайдкар), 4972 passed / 37 skipped (backend).
2026-08-29 14:09:23 +03:00
bot-backend
b9025de666 fix(tradein/domclick): площадка отдаёт одну карточку на процесс браузера, а мы держали один на весь прогон (#3205)
All checks were successful
CI Trade-In / changes (pull_request) Successful in 10s
CI / changes (pull_request) Successful in 10s
CI Trade-In / backend-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 / browser-tests (pull_request) Successful in 1m5s
Замер на проде 2026-08-29. Три независимых запуска camoufox через прод-прокси,
идём по карточкам до первого отказа — каждый раз одно и то же: карточка #1
даёт 200 и ~1 МБ с SSR-стейтом, карточка #2 даёт 401 и страницу отказа на
26 625 байт. A/B на восьми карточках: свой браузер на каждую — 4 из 4 успеха,
один браузер на четыре — 1 из 4. Прямой выход с сервера и выход через прокси
неразличимы (1 из 8 в обоих условиях), то есть дело не в IP.

Свежего КОНТЕКСТА не хватает: в контрольном замере каждая карточка бралась
через browser.new_page(), в новом изолированном контексте, — и всё равно отказ
со второй. Признак живёт на уровне процесса, camoufox генерирует отпечаток при
запуске, а не при создании контекста. Отсюда: reset_context (#3118) эту задачу
не решает в принципе. Цена перезапуска — 0.6 с (3.5 с только первый, холодный).

- PROVIDERS: добавлен "domclick" (+ host-detect). Раньше он проваливался в
  generic и делил браузер со счётчиком страниц с прочим трафиком — при пороге
  перезапуска 1 это было бы неверно.
- BROWSER_RECYCLE_PAGES стал поставщик-зависимым (_resolve_recycle_pages +
  BROWSER_RECYCLE_PAGES_{PROVIDER}), по образцу BROWSER_BLOCK_IMAGES_{PROVIDER}
  из #3185. Код-дефолт domclick=1, остальным прежние 15 — у Авито и Циана узор
  другой и своего замера под него нет.

Отдельно починены ~24 холостых охранника в тестах. Они делали
monkeypatch.setattr(server, "BROWSER_RECYCLE_PAGES", 10_000), чтобы запретить
перезапуск браузера; после перехода на словарь этот патч перестал на что-либо
влиять, и набор оставался зелёным лишь потому, что ни один тест не делает 15
страниц подряд. Теперь патчится _RECYCLE_PAGES_BY_PROVIDER, а сама глобальная
константа убрана, чтобы её не патчили снова. Проверено мутацией: при пороге 1
для всех провайдеров падают ровно три теста, которые этот дефолт и проверяют,
остальные 155 удерживаются — значит охранники работают.
2026-08-29 13:14:20 +03:00