Some checks failed
Deploy Trade-In / changes (push) Successful in 5s
Deploy Trade-In / test (push) Has been skipped
Deploy Trade-In / build-frontend (push) Has been skipped
Deploy Trade-In / build-backend (push) Has been skipped
Deploy Trade-In / build-browser (push) Successful in 2m22s
Deploy Trade-In / deploy (push) Has been cancelled
Co-authored-by: bot-backend <bot-backend@gendsgn.local> Co-committed-by: bot-backend <bot-backend@gendsgn.local>
66 lines
3.7 KiB
Docker
66 lines
3.7 KiB
Docker
# tradein-browser — camoufox Playwright WS server (изолированный контейнер Firefox).
|
||
# Backend подключается к этому контейнеру через playwright.firefox.connect.
|
||
|
||
FROM python:3.12-slim
|
||
|
||
ENV PYTHONUNBUFFERED=1 \
|
||
PYTHONDONTWRITEBYTECODE=1
|
||
|
||
# Firefox runtime libs + ca-certificates для TLS
|
||
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
|
||
--mount=type=cache,target=/var/lib/apt,sharing=locked \
|
||
apt-get update && apt-get install -y --no-install-recommends \
|
||
libgtk-3-0 \
|
||
libasound2 \
|
||
libdbus-glib-1-2 \
|
||
libx11-xcb1 \
|
||
libxtst6 \
|
||
ca-certificates \
|
||
&& useradd --create-home --uid 1000 app
|
||
|
||
WORKDIR /app
|
||
|
||
# camoufox[geoip] тянет playwright как зависимость
|
||
RUN pip install --no-cache-dir "camoufox[geoip]" aiohttp
|
||
|
||
# ── #915: null-guard для pageError.location в playwright 1.60.0 ─────────────────
|
||
# Firefox/juggler-бэкенд иногда отдаёт uncaught JS-ошибку страницы (реклама /
|
||
# cross-origin скрипты на avito) БЕЗ поля location. playwright-диспетчер при
|
||
# доставке pageError-события читает `pageError.location.url` (coreBundle.js,
|
||
# 2 места: BrowserContextDispatcher + trace event) без null-guard →
|
||
# `TypeError: Cannot read properties of undefined (reading 'url')` ВНУТРИ
|
||
# event-хэндлера node-драйвера → рвёт protocol-соединение → "Connection closed
|
||
# while reading from the driver" / TargetClosedError → server.py отдаёт 500 и
|
||
# делает полный relaunch браузера (дорого, тормозит sweep). Недетерминированно:
|
||
# зависит от того, кинет ли конкретная загрузка locationless-ошибку.
|
||
# Апгрейд playwright невозможен — camoufox 0.4.11 pinned под конкретный
|
||
# Firefox+juggler. Чиним optional-chaining'ом прямо в pinned-бандле:
|
||
# `pageError.location.X` → `pageError.location?.X` (no-op когда location есть;
|
||
# отдаёт {url:undefined,...} когда нет → событие доставляется без краша).
|
||
# Сборка падает (exit 1) если паттерн не найден — сигнал что bump playwright
|
||
# сломал патч.
|
||
RUN PW_BUNDLE="$(python -c 'import os,playwright;print(os.path.join(os.path.dirname(playwright.__file__),"driver","package","lib","coreBundle.js"))')" \
|
||
&& sed -i -E 's/pageError\.location\.(url|lineNumber|columnNumber)/pageError.location?.\1/g' "$PW_BUNDLE" \
|
||
&& N="$(grep -cF 'pageError.location?.url' "$PW_BUNDLE")" \
|
||
&& echo "tradein-browser: patched pageError.location?.url sites: $N" \
|
||
&& [ "$N" -ge 2 ]
|
||
|
||
COPY server.py ./server.py
|
||
|
||
# camoufox fetch качает (а) Firefox-сборку и (б) GeoLite2 mmdb (geoip=True).
|
||
# Firefox идёт в $HOME/.cache → ENV HOME=/home/app кладёт его в кэш app-юзера,
|
||
# куда рантайм его ищет (фикс #899). НО mmdb пишется в site-packages пакета
|
||
# camoufox (root-owned после pip install) — под app это PermissionError на
|
||
# GeoLite2-City.mmdb. Поэтому fetch выполняем под ROOT (пишет и mmdb, и —
|
||
# благодаря ENV HOME — Firefox в /home/app/.cache), затем chown'им Firefox-кэш
|
||
# на app. mmdb остаётся root-owned в site-packages (world-readable → app читает
|
||
# на рантайме). Verified реальной сборкой образа 2026-05-31.
|
||
ENV HOME=/home/app
|
||
|
||
RUN python -m camoufox fetch && chown -R app:app /home/app/.cache
|
||
|
||
USER app
|
||
|
||
EXPOSE 3000
|
||
|
||
CMD ["python", "server.py"]
|