Skip to content

fix: clean up Playwright process on browser startup failure - #2165

Closed
Battleplus wants to merge 2 commits into
unclecode:mainfrom
Battleplus:fix/2155-playwright-leak-on-start-failure
Closed

fix: clean up Playwright process on browser startup failure#2165
Battleplus wants to merge 2 commits into
unclecode:mainfrom
Battleplus:fix/2155-playwright-leak-on-start-failure

Conversation

@Battleplus

Copy link
Copy Markdown

这次改了什么

When Playwright starts successfully but Chromium launch fails (e.g. missing browser binary, sandbox issues), the node cli.js run-driver subprocess was leaked. Each failed attempt left one live child process, growing the process count linearly with retries.

Changes:

  1. browser_manager.py: Extract browser launch logic into _launch_browser(), wrap the call in start() with try/except that calls self.playwright.stop() on failure.

  2. async_webcrawler.py: Wrap crawler_strategy.__aenter__() in start() with try/except that calls __aexit__() on failure.

Both layers ensure partial resources are cleaned up before the exception propagates.

怎么验证的

  • Python syntax check passes for both files
  • Manual verification: AsyncWebCrawler.__aenter__() now properly cleans up when browser launch fails
  • No live playwright driver processes remain after failed start attempts

风险

Low. Only adds cleanup on the exception path. Happy path is unchanged.

Closes #2155

Battleplus and others added 2 commits August 20, 2026 22:49
Resolves unclecode#2155

When Playwright starts successfully but Chromium launch fails (e.g.
missing browser binary, sandbox issues), the Playwright driver
subprocess was leaked because no cleanup ran on the exception path.

Each failed attempt left one live `node cli.js run-driver` child
process, growing the process count linearly with retries.

Changes:
- browser_manager.py: Extract browser launch into `_launch_browser()`,
  wrap call in `start()` with try/except that stops Playwright on
  failure
- async_webcrawler.py: Wrap `crawler_strategy.__aenter__()` in
  `start()` with try/except that calls `__aexit__()` on failure

Both layers ensure partial resources are cleaned up before the
exception propagates to the caller.
Signed-off-by: Battleplus <battleplus@users.noreply.github.com>
@Battleplus

Copy link
Copy Markdown
Author

Follow-up audit: startup rollback now catches BaseException, not only Exception, so task cancellation during Playwright/browser startup cannot leak the driver. Added unit coverage for ordinary launch failure, asyncio cancellation at BrowserManager startup, and cancellation while entering AsyncWebCrawler. Validation: 3 passed. Commit: 15a14c9.

@Battleplus

Copy link
Copy Markdown
Author

Closing as a duplicate after the full audit. Earlier PR #2160 wraps the complete BrowserManager startup sequence in BaseException-safe rollback and includes a real Playwright child-process leak regression. This PR was additionally hardened for cancellation and its unit tests passed, but #2160 is earlier and covers more startup branches, so review should stay there.

@Battleplus Battleplus closed this Aug 22, 2026
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.

[Bug]: AsyncWebCrawler leaks Playwright driver process when browser startup fails in __aenter__

1 participant