Skip to content

fix(scraper): don't orphan the browser when a portal session fails to acquire#171

Open
delabrcd wants to merge 1 commit into
mainfrom
fix/portal-session-browser-leak
Open

fix(scraper): don't orphan the browser when a portal session fails to acquire#171
delabrcd wants to merge 1 commit into
mainfrom
fix/portal-session-browser-leak

Conversation

@delabrcd

Copy link
Copy Markdown
Owner

Problem

acquirePortalSession() launched Chromium, then ran newContext / newPage /
ensureLoggedIn unguarded. If any of those threw — a flaky login, an MFA
wall, a nav timeout — the PortalSession object that owns close() was never
returned, so the just-launched browser was orphaned.

The scheduled runner acquires one session per login every tick, so a
persistently failing login orphans a headless-Chrome on every retry. In a
real deployment this accumulated 200+ zombie chrome processes (~7 GiB) on
the non-prod instances, whose National-Grid logins fail. (Prod's login works,
so prod never leaked — which is why it went unnoticed.)

collect.ts had the same bug class in its own-browser path: it created the
context/page before the try/finally, so a throw there leaked too.

Fix

  • session.ts — wrap every post-launch step in try/catch; close() the
    browser before rethrowing. Happy path unchanged (the returned session's
    close() still owns normal teardown).
  • collect.ts — move newContext/newPage inside the try so a throw
    there reaches the finally that closes the own-browser.

Validation

  • 1005/1005 unit tests pass (docker build --target test).
  • Both changed files typecheck clean.
  • No behavior change on the success path.

… acquire

acquirePortalSession() launched chromium, then ran newContext/newPage/
ensureLoggedIn unguarded. If any of those threw (a flaky login, an MFA
wall, a nav timeout) the session object that owns close() was never
returned, so the just-launched browser leaked. The scheduled runner
acquires once per login every tick, so a persistently failing login
piled up one zombie headless-Chrome per retry — observed as 200+ orphan
chrome procs (~7 GiB) across the non-prod instances, whose NG logins
fail (prod's login works, so prod never leaked).

Wrap the post-launch steps in try/catch and close() the browser before
rethrowing. Harden collect.ts the same way: its own-browser path created
the context/page before the try/finally, so a throw there leaked too —
move them inside the try.

No behavior change on the happy path; 1005 unit tests green.
@delabrcd delabrcd force-pushed the fix/portal-session-browser-leak branch from 8a48888 to ba14188 Compare June 25, 2026 18:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant