fix(browser): null-guard pageError.location in playwright bundle (#915) #918
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#918
Loading…
Add table
Reference in a new issue
No description provided.
Delete branch "fix/915-browser-pageerror-500"
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?
Проблема — почему
tradein-browserотдаёт 500Прод-наблюдение (run_32, city-sweep в browser-режиме): ~6 из 21
/fetchвернули 500, каждый форсил полный relaunch браузера (~5-10с) → city-sweep ползёт.Корневая причина (Cause A): avito-страницы во время гидрации иногда кидают uncaught JS-ошибку без поля
location(рекламные / cross-origin скрипты). Firefox/juggler-бэкенд передаёт её сlocation === undefined, а playwright 1.60.0 при доставкеpageError-события читает без null-guard (coreBundle.js, 2 места —BrowserContextDispatcher+ trace-event):TypeError: Cannot read properties of undefined (reading 'url')летит внутри event-хэндлера node-драйвера → рвёт protocol-соединение →Connection closed while reading from the driver/TargetClosedError→server.pyотдаёт 500 и делает full browser relaunch.Почему патчим бандл, а не апгрейдим playwright
Апгрейд playwright невозможен — camoufox 0.4.11 pinned под конкретный Firefox+juggler-build (новый playwright несовместим с браузером в контейнере). Поэтому правим pinned-бандл прямо в образе.
Изменение
browser/Dockerfile: послеpip installдобавлен RUN-шаг, которыйsed'ом меняетpageError.location.{url,lineNumber,columnNumber}→pageError.location?.{...}(optional chaining). No-op когдаlocationесть; когда нет — событие доставляется с{url:undefined,...}без краша.Сборка падает (exit 1), если паттерн не найден (
[ "$N" -ge 2 ]) — громкий сигнал что будущий bump playwright сломал патч.Verify-don't-trust
Прогнал точный
sedпротив развёрнутого бандла в контейнере (temp-копия, неразрушающе):beforeunguardedpageError.location.url: 2afterguardedpageError.location?.url: 2, remaining unguarded: 0node --check(bundled playwright node): OKНе в scope
Page.goto60s timeout на медленных detail-страницах через mobileproxy) — отдельный 500, НЕ матчит_is_browser_crash(без relaunch,BrowserFetcherретраит). Тюнинг тайм-аутов — следующим шагом./fetch-json) — Stage 2/3 эпика #915.Refs #883, #901, #916
Avito pages emit uncaught JS errors without a location (ad / cross-origin scripts); playwright 1.60.0's dispatcher reads pageError.location.url with no null-guard (coreBundle.js ×2: BrowserContextDispatcher + trace event) → TypeError 'Cannot read properties of undefined (reading url)' crashes the node-driver protocol connection → 'Connection closed while reading from the driver' / TargetClosedError → tradein-browser returns 500 and server.py does a full browser relaunch. Proven on prod run_32: ~6/21 /fetch hit 500, each forcing a ~5-10s relaunch and stalling the city-sweep. playwright upgrade is impossible — camoufox 0.4.11 pins the matching Firefox+juggler build. Patch the pinned bundle in-image: pageError.location.{url,lineNumber,columnNumber} -> optional chaining (no-op when location is present). Build asserts >=2 sites patched, failing loudly on a future playwright bump. Verified against the deployed bundle: 2 unguarded -> 2 guarded, 0 remaining, node --check OK. Refs #883, #901, #916✅ APPROVE — корректный low-risk bundle-патч с громким failure mode. Мержу.
Корректность
sed -E 's/pageError\.location\.(url|lineNumber|columnNumber)/pageError.location?.\1/g'→ optional chaining. КогдаpageError.location === undefined,location?.urlотдаётundefinedвместо throw — ровно устраняетTypeError, который рвал protocol-соединение и форсил relaunch (500). ✓location?.urlуже не матчит литерал-дот regexlocation\.url(междуlocationиurlстоит?, не.). ✓[ "$N" -ge 2 ]: если будущий bump playwright изменит бандл — sed ничего не заменит → guard падает → сборка валится в CI, сломанный образ не уезжает. Неверный путь → sed ошибается на отсутствующем файле → build fail. Само-валидируется. ✓grep -cF= 2 (значит 2 сайта на разных строках → guard>= 2держится для этой версии) +node --checkOK. ✓Risk
build-browser). Плохой патч = fail build = ловится в CI до деплоя, прод остаётся на старом образе. Zero prod blast radius на failure.browser/Dockerfile, без секретов. Закрывает Cause A из run_32 (~6/21/fetch→ 500 + relaunch).Cause B (goto 60s timeout) и IMV/Stage 2-3 осознанно вне scope — ок.
Squash-merge + delete branch. #915 уже в qa — этот fix усиливает browser-стабильность того же эпика.