[EPIC] proxy-pool — хранилище прокси в БД + автовыбор свободного/рабочего #2160

Closed
opened 2026-07-02 16:25:04 +00:00 by lekss361 · 1 comment
Owner

Цель

Заменить захардкоженные в env прокси на пул в БД: загрузил список → система сама выбирает свободный + рабочий прокси, ведёт health, при бане берёт следующий. Full-интеграция (curl-пути + динамический browser).

Текущее состояние (заменяем)

Прокси в env: per-provider BROWSER_PROXY_{AVITO,CIAN,YANDEX} (http для camoufox) + legacy *_PROXY_URL (socks5 для curl) + SCRAPER_PROXY_URL (generic). Один фиксированный на провайдера; смена = правка env + релонч. Таблицы нет. Ротация IP — changeip на стороне mobileproxy.

Дизайн (Anton, 2026-07-02: Full + lease/affinity)

Таблица scrape_proxies:

  • url (или scheme/host/port/username/password), provider_affinity (avito/cian/yandex/generic/any — сохраняем per-provider изоляцию против rate-cap NS_ERROR_PROXY_TOO_MANY_REQUESTS), rotate_url (changeip, nullable), kind (http/socks5)
  • enabled bool
  • health: last_check_at, last_ok_at, consecutive_fails, exit_ip, latency_ms
  • lease: leased_by (run_id, nullable), leased_at — «свободный» = leased_by IS NULL
  • meta: geo, operator, expires_at, created_at, label

Сервис proxy_pool:

  • acquire(provider)SELECT ... WHERE enabled AND healthy AND affinity IN (provider,'any') AND leased_by IS NULL ORDER BY last_ok_at NULLS LAST FOR UPDATE SKIP LOCKED LIMIT 1 → UPDATE leased. Второй параллельный проход провайдера берёт следующий свободный.
  • release(proxy_id) → leased_by=NULL. mark_health(id, ok, exit_ip, latency).
  • «healthy» = consecutive_fails < N (порог из конфига).

Health-checker: периодическая задача (scheduler source proxy_healthcheck) — пинг каждого enabled через ipify → ok/fail, update health, авто-disable после N фейлов.

Загрузка: admin-ручка bulk-INSERT (список url+affinity) / CSV; seed текущих env-прокси в таблицу при миграции.

Интеграция (Full):

  • curl-пути (valuation/imv/detail-curl) → acquire/release из пула вместо env
  • browser server → динамический acquire(provider) на /fetch, relaunch camoufox-инстанса при смене прокси, release после

Под-issues (волнами, QA между)

  • P1 таблица scrape_proxies + admin bulk-load + seed env-прокси — аддитивно, безопасно
  • P2 сервис proxy_pool (acquire/release/mark_health) + health-checker task — аддитивно (не подключён к бою), depends P1
  • P3 интеграция curl-путей (scrapers берут из пула) — рискованно, прод-QA, depends P2
  • P4 динамический browser server (acquire + relaunch + release) — рискованно, прод-QA, depends P2

Что НЕ делать

  • Убрать per-provider изоляцию (rate-cap известен)
  • Интегрировать P3/P4 без прод-QA на живом sweep (меняет боевой сбор)
  • Хардкодить креды прокси в коде/коммитах (загрузка данных — через admin/seed, секреты в env/vault)

Связано

  • Прокси-архитектура: vault Module_Scraper_Browser_Proxy_Architecture, Module_Tradein_Scrapers_Fetch_Arch, Decision_P0_Per_Source_Browser_Proxy_Plan_Jun18
  • Живёт в боевом app/services (kit ещё не в бою); при rewire scraper-kit — proxy_pool инжектируется в kit (как HouseMatcher)
## Цель Заменить захардкоженные в env прокси на пул в БД: загрузил список → система сама выбирает **свободный + рабочий** прокси, ведёт health, при бане берёт следующий. Full-интеграция (curl-пути + динамический browser). ## Текущее состояние (заменяем) Прокси в env: per-provider `BROWSER_PROXY_{AVITO,CIAN,YANDEX}` (http для camoufox) + legacy `*_PROXY_URL` (socks5 для curl) + `SCRAPER_PROXY_URL` (generic). Один фиксированный на провайдера; смена = правка env + релонч. Таблицы нет. Ротация IP — changeip на стороне mobileproxy. ## Дизайн (Anton, 2026-07-02: Full + lease/affinity) **Таблица `scrape_proxies`:** - `url` (или scheme/host/port/username/password), `provider_affinity` (avito/cian/yandex/generic/any — **сохраняем per-provider изоляцию** против rate-cap `NS_ERROR_PROXY_TOO_MANY_REQUESTS`), `rotate_url` (changeip, nullable), `kind` (http/socks5) - `enabled` bool - health: `last_check_at`, `last_ok_at`, `consecutive_fails`, `exit_ip`, `latency_ms` - lease: `leased_by` (run_id, nullable), `leased_at` — «свободный» = `leased_by IS NULL` - meta: `geo`, `operator`, `expires_at`, `created_at`, `label` **Сервис `proxy_pool`:** - `acquire(provider)` → `SELECT ... WHERE enabled AND healthy AND affinity IN (provider,'any') AND leased_by IS NULL ORDER BY last_ok_at NULLS LAST FOR UPDATE SKIP LOCKED LIMIT 1` → UPDATE leased. Второй параллельный проход провайдера берёт следующий свободный. - `release(proxy_id)` → leased_by=NULL. `mark_health(id, ok, exit_ip, latency)`. - «healthy» = `consecutive_fails < N` (порог из конфига). **Health-checker:** периодическая задача (scheduler source `proxy_healthcheck`) — пинг каждого enabled через ipify → ok/fail, update health, авто-disable после N фейлов. **Загрузка:** admin-ручка bulk-INSERT (список url+affinity) / CSV; seed текущих env-прокси в таблицу при миграции. **Интеграция (Full):** - curl-пути (valuation/imv/detail-curl) → acquire/release из пула вместо env - browser server → динамический acquire(provider) на /fetch, relaunch camoufox-инстанса при смене прокси, release после ## Под-issues (волнами, QA между) - [ ] P1 таблица `scrape_proxies` + admin bulk-load + seed env-прокси — **аддитивно, безопасно** - [ ] P2 сервис `proxy_pool` (acquire/release/mark_health) + health-checker task — аддитивно (не подключён к бою), depends P1 - [ ] P3 интеграция curl-путей (scrapers берут из пула) — **рискованно, прод-QA**, depends P2 - [ ] P4 динамический browser server (acquire + relaunch + release) — **рискованно, прод-QA**, depends P2 ## Что НЕ делать - ❌ Убрать per-provider изоляцию (rate-cap известен) - ❌ Интегрировать P3/P4 без прод-QA на живом sweep (меняет боевой сбор) - ❌ Хардкодить креды прокси в коде/коммитах (загрузка данных — через admin/seed, секреты в env/vault) ## Связано - Прокси-архитектура: vault `Module_Scraper_Browser_Proxy_Architecture`, `Module_Tradein_Scrapers_Fetch_Arch`, `Decision_P0_Per_Source_Browser_Proxy_Plan_Jun18` - Живёт в боевом `app/services` (kit ещё не в бою); при rewire scraper-kit — proxy_pool инжектируется в kit (как HouseMatcher)
lekss361 added the
data
enhancement
scope/backend
scrapers
tradein
labels 2026-07-02 16:26:02 +00:00
Author
Owner

Закрыто: proxy-pool активен на проде (Full-интеграция, 2026-07-03)

Итог: USE_PROXY_POOL_CURL=true + USE_PROXY_POOL_BROWSER=true постоянно в docker-compose.prod.yml (PR #2268). curl-пути и browser-пути (yandex/cian/avito SERP через camoufox) берут прокси из scrape_proxies (acquire → mark_health → release, FOR UPDATE SKIP LOCKED).

Прод-QA:

  • Ротация вживую: 5 прокси, lease по кругу, утечек нет (leased_by освобождается на каждом цикле, включая исключения — release в finally).
  • Cian: баны ушли — runs #564/#574 (banned через один env-прокси ha) → #586 фетчит стабильно 28 lots/страницу через пул. Причина исходной проблемы подтверждена: ha перегружался camoufox-нагрузкой, пул размазал её по 5 прокси.
  • Avito (бан-чувствительный): SERP 66 lots/3 страницы, ротация id=1→4→5, банов нет.
  • health-checker (proxy_healthcheck) обновляет exit_ip/latency каждые 30 мин, consecutive_fails=0 у всех.

Известная цена: camoufox relaunch при каждой смене прокси → 13-45s/страница. Watchdog cian отмасштабирован (PR #2272). Оптимизация (sticky lease per-anchor / affinity) — возможный follow-up, не блокер.

Косметика в follow-up: leased_by=-1 (sentinel вместо run_id), exit_ip=None в mark_health на fetch-пути, %ds%.0fs в WARNING-логе cian.

## Закрыто: proxy-pool активен на проде (Full-интеграция, 2026-07-03) **Итог:** `USE_PROXY_POOL_CURL=true` + `USE_PROXY_POOL_BROWSER=true` постоянно в `docker-compose.prod.yml` (PR #2268). curl-пути и browser-пути (yandex/cian/avito SERP через camoufox) берут прокси из `scrape_proxies` (acquire → mark_health → release, FOR UPDATE SKIP LOCKED). **Прод-QA:** - Ротация вживую: 5 прокси, lease по кругу, утечек нет (leased_by освобождается на каждом цикле, включая исключения — release в finally). - Cian: баны ушли — runs #564/#574 (`banned` через один env-прокси ha) → #586 фетчит стабильно 28 lots/страницу через пул. Причина исходной проблемы подтверждена: ha перегружался camoufox-нагрузкой, пул размазал её по 5 прокси. - Avito (бан-чувствительный): SERP 66 lots/3 страницы, ротация id=1→4→5, банов нет. - health-checker (`proxy_healthcheck`) обновляет exit_ip/latency каждые 30 мин, consecutive_fails=0 у всех. **Известная цена:** camoufox relaunch при каждой смене прокси → 13-45s/страница. Watchdog cian отмасштабирован (PR #2272). Оптимизация (sticky lease per-anchor / affinity) — возможный follow-up, не блокер. **Косметика в follow-up:** `leased_by=-1` (sentinel вместо run_id), `exit_ip=None` в mark_health на fetch-пути, `%ds`→`%.0fs` в WARNING-логе cian.
Sign in to join this conversation.
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#2160
No description provided.