Skip to content

Cancel timed-out Playwright executions - #327

Open
masnwilliams wants to merge 1 commit into
mainfrom
hypeship/cancel-playwright-timeouts
Open

Cancel timed-out Playwright executions#327
masnwilliams wants to merge 1 commit into
mainfrom
hypeship/cancel-playwright-timeouts

Conversation

@masnwilliams

@masnwilliams masnwilliams commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

summary

  • disconnect the persistent Playwright CDP client when an execution reaches its request timeout
  • prevent abandoned scripts from continuing to mutate browser state after the timeout response
  • reconnect transparently for the next execution
  • extend the timeout regression test to detect delayed page mutations

proof

The reproduction starts a script that alternates scrollIntoViewIfNeeded() between top and bottom targets every 500ms. After ten iterations it sets a marker to late-finished. The request timeout is shorter than the script, so any marker or scroll changes after the timeout response are escaped execution.

before: main

The API returned the timeout after approximately one second, but the script remained live:

{
  "timeout": { "success": false, "elapsed_ms": 1004 },
  "immediate": { "marker": "initial" },
  "after_2_seconds": { "marker": "late" }
}

The post-timeout mutation reproduces consistently with both the production endpoint and a local Chromium daemon built from main.

after: this branch

Built the complete headless image from this branch (sha256:b02c5efcc8a1e06933f38b163326b1f65f6dc144267c2706cee787ea48c01101) and ran the same alternating-scroll request through the image's /playwright/execute endpoint:

{
  "timeout": { "success": false, "elapsed_ms": 2015 },
  "immediate": { "marker": "step-3", "scroll_y": 0 },
  "after_4_seconds": { "marker": "step-3", "scroll_y": 0 }
}

The marker and scroll position remain unchanged after the timeout. The abandoned script does not reach late-finished or perform another scroll. A subsequent Playwright request reconnects and succeeds against the same browser page.

The image-level regression also passes:

=== RUN   TestPlaywrightExecuteTimeoutReturnsPromptlyAndRecovers
playwright timeout regression test passed
--- PASS: TestPlaywrightExecuteTimeoutReturnsPromptlyAndRecovers (8.16s)

validation

  • verified the standalone daemon fix with both Playwright and Patchright against local Chromium
  • built the full headless image from this branch
  • ran TestPlaywrightExecuteTimeoutReturnsPromptlyAndRecovers against the built image
  • reran the alternating-scroll reproduction through the built image's real API endpoint
  • bun build server/runtime/playwright-daemon.ts --outfile=/tmp/playwright-daemon.js --target=node --external playwright-core --external patchright --external esbuild
  • go vet ./...
  • go test -v -race $(go list ./... | grep -v /e2e$)

@masnwilliams
masnwilliams requested a review from rgarcia August 7, 2026 18:09

@rgarcia rgarcia left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reviewed — looks good. the timeout now interrupts the abandoned Playwright execution, reconnects cleanly for the next request, and the regression test covers both recovery and delayed page mutations.

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.

2 participants