feat(browser): split camoufox into a separate tradein-browser container (Phase 0.5, #905) #907
No reviewers
Labels
No labels
admin
analytics
auth
automation
bug
business
chore
ci
compliance
data
data-moat
docs
duplicate
dx
enhancement
Fable 5 ревью
feedback/max
generative
GG-форсайт
needs-discussion
needs-human
observability
pause-bots
performance
priority/p0
priority/p1
priority/p2
priority/p3
scope/backend
scope/db
scope/devops
scope/frontend
scope/qa
scrapers
security
site-finder
stage/1
stage/2
status/blocked
status/done
status/needs-analysis
status/needs-fix
status/qa
status/ready
status/review
status/wip
tech-debt
tradein
ux
week ревью 1
wontfix
вторичка
ИРД
No milestone
No project
No assignees
2 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: lekss361/gendesign#907
Loading…
Add table
Reference in a new issue
No description provided.
Delete branch "feat/884-browser-separate-container"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Revises #884's in-backend camoufox into a dedicated
tradein-browserservice (your call — browser shouldn't live in the API container). Confirmed feasible via camoufox docs:camoufox.server.launch_server(...)exposes a Playwright WS endpoint with fingerprint/geoip/proxy configured server-side; the backend connects remotely with plainplaywrightand no longer ships Firefox.Architecture
launch_serveron :3000mem_limit: 2.5gmoved hereplaywrightclient →connect(ws)only — Firefox libs + camoufox droppedmem_limitremovedChanges
tradein-mvp/browser/{server.py,Dockerfile}— camoufox WS server; Firefox fetch underappuser +ENV HOME(carries the #899 cache-path fix so it doesn't repeat the root-vs-app bug).browser_fetcher.pyrewritten: launch-in-process →playwright.firefox.connect(settings.browser_ws_endpoint); recycle (close+reconnect every N) + crash-recovery (TargetClosed → reconnect + 1 retry) preserved.camoufox[geoip], promotesplaywrightto main deps.browserservice, removemem_limitfrom backend,backend depends_on browser.browser_ws_endpointdefaultws://tradein-browser:3000/playwright.build-browserjob +browserpath-filter +IMAGE_BROWSERenv, wired intodeployneeds/gate (so the image exists before compose pulls it — otherwise deploy would break on a missing image).Verified
launch_serversignature checked (**kwargs→launch_options;portpasses through; nohostparam — Playwright binds all interfaces by default).playwright.firefox.connectneeds no camoufox/Firefox on the client.tests/scrapers/test_browser_fetcher.pyrewritten for connect-mode → 6 pass (lifecycle, recycle, reconnect, counter-reset, crash-retry, error-propagation).import browser_fetcherworks without camoufox installed.Risk / dormancy
scraper_fetch_modestayscurl_cffi→ no prod runtime behavior change. The browser is never exercised at runtime until Phase 1 (#901) flips a source to browser-mode. Merging does change the deploy topology (new container, slimmer backend image) — thebuild-browserjob +depends_onhandle ordering. Docker images not built locally (no Docker in the worker env) — CI build-browser is the real verification; recommend confirming that job goes green before/at merge.Supersedes the in-backend approach of #884. Refs #905, #883, #884, #899, #901
Manual review (code-reviewer subagent) — ⚠️ MINOR
Корректность/безопасность — без блокеров. Deploy-risk низкий (browser dormant:
scraper_fetch_modeостаётсяcurl_cffi, runtime не меняется до Phase 1).👍 Сильно
build-browserвneedsdeploy-job + gate наresult != 'failure', параллельно с frontend. Образ окажется в GHCR доcompose pull.browser:+infra:— нет false-negative для нового сервиса.USER app+ENV HOMEпередcamoufox fetch(Firefox под app-юзером)._close()/_reconnect()без утечек (_pw.stop()вfinally, page-counter сброс на close); crash-recovery тест проверяетconnect.await_count == 2.scraper_fetch_mode=browser. Backend Dockerfile слиммлен корректно (5 Firefox-либ убраны, есть в browser/). pyproject:camoufox[geoip]убран,playwrightпромоутнут.🔧 Перед merge / до Phase 1
docker-compose.prod.ymldepends_on browser: service_startedне гарантирует готовность WS (Firefox init 5-15с). При Phase-1 флипе backend упадёт наconnect(). Нуженhealthcheckна browser +condition: service_healthy. Сейчас безопасно (dormant) — можно отложить, но до флипа обязательно.deploy-tradein.ymlcleanup-loop не чистит browser-образ (~1GB) → SHA-тегнутые старые образы копятся на VPS. Добавитьghcr.io/lekss361/gendesign-tradein-browserв for-loop.server.pylaunch_server(port=...)безhost=— проверить, что биндит0.0.0.0, не loopback (иначе backend-контейнер не достучится). Smoke на первом деплое:docker exec tradein-backend curl -sv ws://tradein-browser:3000. Если default не0.0.0.0— передатьhost="0.0.0.0"явно.Post-merge polish
test_browser_fetcher.py:27,34—proxy_url/scraper_proxy_urlв mock-settings dead (proxy теперь server-side); убрать.Перед первым деплоем:
df -h /var/lib/docker(первыйcompose upтянет ~1GB образ).Это ручной advisory-review (main-сессия). Финальный verdict + merge — за auto-code-reviewer.