From b238d3ef5054999ac20f6960c2fe9462d6ee2326 Mon Sep 17 00:00:00 2001 From: bot-backend Date: Sat, 4 Jul 2026 17:21:07 +0300 Subject: [PATCH] =?UTF-8?q?chore(tradein/proxy-pool):=20=D0=B4=D0=BE=D0=B1?= =?UTF-8?q?=D0=B0=D0=B2=D0=B8=D1=82=D1=8C=20domclick=20=D0=B2=20provider?= =?UTF-8?q?=5Faffinity=20CHECK=20(residential=20ASocks=20=D0=B4=D0=BB?= =?UTF-8?q?=D1=8F=20#2000)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tradein-mvp/backend/app/api/v1/admin.py | 2 +- ...3_scrape_proxies_add_domclick_affinity.sql | 53 +++++++++++++++++++ 2 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 tradein-mvp/backend/data/sql/173_scrape_proxies_add_domclick_affinity.sql diff --git a/tradein-mvp/backend/app/api/v1/admin.py b/tradein-mvp/backend/app/api/v1/admin.py index a2e1fbbc..c67a633a 100644 --- a/tradein-mvp/backend/app/api/v1/admin.py +++ b/tradein-mvp/backend/app/api/v1/admin.py @@ -2465,7 +2465,7 @@ def get_data_quality( # АДДИТИВНО: ручки лишь наполняют/читают scrape_proxies. Подключение пула к # боевому сбору (pick/lease/rotate вместо env) — отдельные шаги P3/P4. -_PROXY_AFFINITIES = frozenset({"avito", "cian", "yandex", "generic", "any"}) +_PROXY_AFFINITIES = frozenset({"avito", "cian", "yandex", "domclick", "generic", "any"}) _PROXY_KINDS = frozenset({"http", "socks5"}) diff --git a/tradein-mvp/backend/data/sql/173_scrape_proxies_add_domclick_affinity.sql b/tradein-mvp/backend/data/sql/173_scrape_proxies_add_domclick_affinity.sql new file mode 100644 index 00000000..ab6e2252 --- /dev/null +++ b/tradein-mvp/backend/data/sql/173_scrape_proxies_add_domclick_affinity.sql @@ -0,0 +1,53 @@ +-- 173_scrape_proxies_add_domclick_affinity.sql +-- Расширение CHECK-констрейнта scrape_proxies.provider_affinity значением 'domclick' (#2000). +-- +-- WHY: +-- DomClick-скрейпинг карточек (scraper_kit/providers/domclick/serp.py:327, +-- build_browser_fetcher(config, "domclick") -> proxy_provider.acquire("domclick")) +-- сейчас попадает в общий пул affinity='any' вместе с мобильными прокси, которые +-- QRATOR банит 403. Есть выделенный residential ASocks-прокси (прод +-- scrape_proxies.id=1) с чистой репутацией IP — живой аудит подтвердил, что QRATOR +-- пропускает чистые residential IP. Хотим закрепить его строго за DomClick через +-- provider_affinity='domclick', а не 'any'. +-- +-- WHAT: +-- DROP + ADD CHECK constraint scrape_proxies_provider_affinity_check с добавленным +-- значением 'domclick' (нельзя ALTER CHECK в Postgres без пересоздания). +-- Реальное имя констрейнта подтверждено в проде через pg_constraint: +-- conname = scrape_proxies_provider_affinity_check +-- CHECK ((provider_affinity = ANY (ARRAY['avito','cian','yandex','generic','any']))) +-- +-- SCOPE: +-- Только схема (CHECK). Данные НЕ трогаем — UPDATE scrape_proxies SET +-- provider_affinity='domclick' WHERE id=1 применяется отдельно, ПОСЛЕ этой миграции +-- (constraint должен допускать значение раньше, чем строка его получит). +-- Backend-уровень (Pydantic whitelist _PROXY_AFFINITIES в admin.py) обновлён в этом +-- же PR — держим в синхроне со схемой. +-- +-- IDEMPOTENCY / SAFETY: +-- - BEGIN/COMMIT — атомарно. +-- - DROP CONSTRAINT IF EXISTS — безопасно, если констрейнт уже пересоздан/переименован. +-- - ADD CONSTRAINT без IF NOT EXISTS (Postgres такого синтаксиса не имеет для +-- constraints) — обёрнуто в DO $$ ... EXCEPTION WHEN duplicate_object THEN NULL, +-- чтобы повторный прогон (после DROP IF EXISTS не сработавшего, т.к. кто-то уже +-- добавил новый constraint с тем же именем) не падал auto-apply на деплое. +-- +-- Dependencies: 157_scrape_proxies.sql + +BEGIN; + +ALTER TABLE scrape_proxies + DROP CONSTRAINT IF EXISTS scrape_proxies_provider_affinity_check; + +DO $$ +BEGIN + ALTER TABLE scrape_proxies + ADD CONSTRAINT scrape_proxies_provider_affinity_check + CHECK (provider_affinity IN + ('avito', 'cian', 'yandex', 'domclick', 'generic', 'any')); +EXCEPTION + WHEN duplicate_object THEN + NULL; -- констрейнт с таким именем уже существует (повторный прогон) — no-op +END $$; + +COMMIT;