[tradein][scrapers][devops] Phase 0.5 — вынести camoufox в отдельный tradein-browser сервис (server/connect) (#883) #905

Closed
opened 2026-05-31 14:12:41 +00:00 by bot-backend · 3 comments
Collaborator

Ревизия архитектуры Phase 0 (#884): camoufox сейчас запечён В образ tradein-backend и поднимает Firefox в процессе бэка (mem_limit 2.5g, образ 3.15ГБ, crash Firefox рискует API/scheduler). Выносим браузер в отдельный контейнер — подтверждено feasible: camoufox官 поддерживает launch_server (WS Playwright-сервер) с сохранением fingerprint/geoip/proxy.

Архитектура

  • Новый сервис tradein-browser (docker-compose.prod.yml + новый tradein-mvp/browser/Dockerfile): запускает camoufox.server.launch_server(headless=True, os="windows", locale="ru-RU", geoip=True, humanize=True, proxy=<из env>, port=3000) на 0.0.0.0:3000. Несёт camoufox + Firefox-build (python -m camoufox fetch) + 5 Firefox-libs + mem_limit: 2.5g. restart: unless-stopped, в сети tradein-net. Cache-path фикс (#899) применить и здесь — fetch под app-юзером + HOME.
  • tradein-backend худеет: из его Dockerfile убрать RUN python -m camoufox fetch + 5 Firefox-libs (libgtk-3-0 libasound2 libdbus-glib-1-2 libx11-xcb1 libxtst6); из compose убрать mem_limit: 2.5g. Зависимость camoufox[geoip] в pyproject оставить (нужен camoufox.server? нет — на бэке только клиент) → проверить: для firefox.connect(ws) нужен лишь playwright; если так — camoufox остаётся ТОЛЬКО в browser-образе, бэк держит playwright.
  • BrowserFetcher (browser_fetcher.py) переписать с launch-in-process на connect: async with async_playwright() as p: browser = await p.firefox.connect(settings.browser_ws_endpoint). Сохранить recycle (close+reconnect каждые N) и crash-recovery (обрыв ws → reconnect + 1 retry). Убрать локальный AsyncCamoufox launch.
  • config: browser_ws_endpoint: str = "ws://tradein-browser:3000/playwright". proxy/fingerprint-настройки переезжают в browser-сервис (env).

Перед кодом — verify (воркер делает первым делом)

  • uv run python -c "import inspect, camoufox.server as s; print(inspect.signature(s.launch_server))" — точная сигнатура launch_server (есть ли port, host, ws_path, humanize, locale).
  • Подтвердить, что playwright.firefox.connect(ws) НЕ требует camoufox/Firefox на клиенте.

Не делать

  • НЕ менять дефолт scraper_fetch_mode (остаётся curl_cffi, dormant).
  • НЕ трогать парсеры / avito-логику (это Phase 1, #901).

DoD

  • tradein-browser сервис в compose + browser/Dockerfile (camoufox + fetch под app + HOME, как #899).
  • backend Dockerfile без camoufox-fetch + Firefox-libs; compose без mem_limit на backend.
  • BrowserFetcher на connect-режиме; recycle + crash-recovery сохранены; unit-тесты (мок playwright connect) зелёные.
  • uv run ruff check clean. Образ backend заметно меньше (проверка размера — devops/CI).
  • Dormant: scraper_fetch_mode=curl_cffi → поведение прода не меняется.

Refs #883, #884, #899, #901

Ревизия архитектуры Phase 0 (#884): camoufox сейчас запечён В образ `tradein-backend` и поднимает Firefox в процессе бэка (mem_limit 2.5g, образ 3.15ГБ, crash Firefox рискует API/scheduler). Выносим браузер в отдельный контейнер — подтверждено feasible: camoufox官 поддерживает `launch_server` (WS Playwright-сервер) с сохранением fingerprint/geoip/proxy. ## Архитектура - **Новый сервис `tradein-browser`** (`docker-compose.prod.yml` + новый `tradein-mvp/browser/Dockerfile`): запускает `camoufox.server.launch_server(headless=True, os="windows", locale="ru-RU", geoip=True, humanize=True, proxy=<из env>, port=3000)` на `0.0.0.0:3000`. Несёт camoufox + Firefox-build (`python -m camoufox fetch`) + 5 Firefox-libs + `mem_limit: 2.5g`. `restart: unless-stopped`, в сети `tradein-net`. **Cache-path фикс (#899) применить и здесь** — fetch под app-юзером + `HOME`. - **`tradein-backend` худеет**: из его Dockerfile убрать `RUN python -m camoufox fetch` + 5 Firefox-libs (`libgtk-3-0 libasound2 libdbus-glib-1-2 libx11-xcb1 libxtst6`); из compose убрать `mem_limit: 2.5g`. Зависимость `camoufox[geoip]` в pyproject **оставить** (нужен `camoufox.server`? нет — на бэке только клиент) → **проверить**: для `firefox.connect(ws)` нужен лишь `playwright`; если так — camoufox остаётся ТОЛЬКО в browser-образе, бэк держит `playwright`. - **`BrowserFetcher` (browser_fetcher.py)** переписать с launch-in-process на **connect**: `async with async_playwright() as p: browser = await p.firefox.connect(settings.browser_ws_endpoint)`. Сохранить recycle (close+reconnect каждые N) и crash-recovery (обрыв ws → reconnect + 1 retry). Убрать локальный `AsyncCamoufox` launch. - **config**: `browser_ws_endpoint: str = "ws://tradein-browser:3000/playwright"`. proxy/fingerprint-настройки переезжают в browser-сервис (env). ## Перед кодом — verify (воркер делает первым делом) - `uv run python -c "import inspect, camoufox.server as s; print(inspect.signature(s.launch_server))"` — точная сигнатура `launch_server` (есть ли `port`, `host`, `ws_path`, `humanize`, `locale`). - Подтвердить, что `playwright.firefox.connect(ws)` НЕ требует camoufox/Firefox на клиенте. ## Не делать - НЕ менять дефолт `scraper_fetch_mode` (остаётся `curl_cffi`, dormant). - НЕ трогать парсеры / avito-логику (это Phase 1, #901). ## DoD - [ ] `tradein-browser` сервис в compose + `browser/Dockerfile` (camoufox + fetch под app + HOME, как #899). - [ ] backend Dockerfile без camoufox-fetch + Firefox-libs; compose без mem_limit на backend. - [ ] `BrowserFetcher` на connect-режиме; recycle + crash-recovery сохранены; unit-тесты (мок playwright connect) зелёные. - [ ] `uv run ruff check` clean. Образ backend заметно меньше (проверка размера — devops/CI). - [ ] Dormant: `scraper_fetch_mode=curl_cffi` → поведение прода не меняется. Refs #883, #884, #899, #901
bot-backend added the
status/wip
label 2026-05-31 14:13:14 +00:00
bot-backend self-assigned this 2026-05-31 14:13:14 +00:00
bot-backend added
status/review
and removed
status/wip
labels 2026-05-31 14:31:02 +00:00
lekss361 added
status/qa
and removed
status/review
labels 2026-06-06 18:43:19 +00:00
Owner

Status actualize (06.06): Phase 0.5 влита в main через PR #912 (commit 9d357f0, camoufox в отдельный tradein-browser). Открытых PR нет. status/reviewstatus/qa.

Status actualize (06.06): Phase 0.5 влита в `main` через PR #912 (commit `9d357f0`, camoufox в отдельный tradein-browser). Открытых PR нет. `status/review` → `status/qa`.
Author
Collaborator

⚠️ qa BLOCKED: контейнер tradein-browser (камуфокс-сплит этого issue) крашлупит 3141 раз (ExitCode=1). Root cause: camoufox geoip=True + proxy делает eager public_ip(proxy) на старте → InvalidProxy т.к. mproxy.site ЛЕЖИТ → _on_startup падает → exit → ∞ restart. Архитектура сплита (отдельный сервис) ШИПнута корректно, но (1) внешний прокси down (домен Anton — подписка/доступ), (2) resilience-gap: сервис не должен крашлупить при down-прокси. Готовлю fix(browser): startup-resilience + background-retry + 503 (без обхода прокси) — отдельный PR. НЕ закрываю пока контейнер красный. Доп: креды прокси (user:pass@mproxy.site) светятся в crash-логах открытым текстом.

⚠️ qa BLOCKED: контейнер `tradein-browser` (камуфокс-сплит этого issue) крашлупит **3141 раз** (ExitCode=1). Root cause: camoufox `geoip=True` + proxy делает eager `public_ip(proxy)` на старте → `InvalidProxy` т.к. `mproxy.site` ЛЕЖИТ → `_on_startup` падает → exit → ∞ restart. Архитектура сплита (отдельный сервис) ШИПнута корректно, но (1) внешний прокси down (домен Anton — подписка/доступ), (2) resilience-gap: сервис не должен крашлупить при down-прокси. Готовлю fix(browser): startup-resilience + background-retry + 503 (без обхода прокси) — отдельный PR. НЕ закрываю пока контейнер красный. Доп: креды прокси (`user:pass@mproxy.site`) светятся в crash-логах открытым текстом.
Author
Collaborator

Закрыто — camoufox вынесен в отдельный сервис tradein-browser (HTTP server, POST /fetch), живёт на проде (Up 5+ дней). BrowserFetchertradein-browser:3000/fetch (см. #884). Phase 0.5 завершена.

✅ Закрыто — camoufox вынесен в отдельный сервис `tradein-browser` (HTTP server, POST /fetch), живёт на проде (Up 5+ дней). `BrowserFetcher` → `tradein-browser:3000/fetch` (см. #884). Phase 0.5 завершена.
Sign in to join this conversation.
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#905
No description provided.