Skip to content

fix(execution): let an unread fetch body release the guest event loop - #2067

Merged
eersnington merged 1 commit into
mainfrom
fix/fetch-unread-body-liveness
Oct 21, 2026
Merged

eersnington merged 1 commit into
mainfrom
fix/fetch-unread-body-liveness

Conversation

@eersnington

Copy link
Copy Markdown
Member

Fixes the remaining part of #1989.

A guest fetch whose response body was never read kept the guest process alive (over 90 s, or forever on a keep-alive loopback server), and javascript.evaluate("(await fetch(url)).status") returned timed_out.

  • Cause: the undici shim's finished() polled web stream state with setTimeout(poll, 0). An unread body never closes, so a ref'd timer re-armed about every millisecond. The socket and keep-alive pool accounting were already correct.
  • finished() now subscribes to the stream's state transition instead of polling, so it holds no event-loop reference, like Node's eos. An in-flight request still keeps the process alive.
Guest script fetches a keep-alive server and does not read the body main This PR
Process exit never (test timeout) under 1 s

@railway-app

railway-app Bot commented Oct 21, 2026

Copy link
Copy Markdown

This PR was not deployed automatically as @eersnington does not have access to the Railway project.

In order to get automatic PR deploys, please add @eersnington to your workspace on Railway.

@github-actions

github-actions Bot commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

📟 Pip-Boy · adfc1cf

📦 Packages · fresh npm install resolve, no lockfile · this PR vs base

No notable install size, dependency, or entrypoint changes across 6 packages.

All 6 packages · linux-x64-gnu
package (linux-x64-gnu) @latest base this PR Δ vs base packages
@rivet-dev/agentos-core 458.2 MB 325.9 MB 325.9 MB 0 10 (0)
@rivet-dev/agentos-node-pty 7.6 KB 18.0 KB 18.0 KB 0 1 (0)
@rivet-dev/agentos-posix 253.6 MB 253.6 MB 253.6 MB 0 7 (0)
@rivet-dev/agentos-runtime-core 253.6 MB 253.6 MB 253.6 MB 0 6 (0)
@rivet-dev/agentos-sandbox 495.5 MB 363.5 MB 363.5 MB 0 85 (0)
@rivet-dev/agentos-toolchain 130.8 KB 141.2 KB 141.2 KB 0 2 (0)

🧹 Rust dependencies

Skipped: this PR doesn't change any Rust code or dependencies.

🦀 Binaries

Skipped: this PR doesn't change any Rust code.

⏱ Timing

job wall time slowest step
changes 29s checkout · 26s
zizmor 9s checkout · 3s
footprint 1m30s Pack this commit · 27s
⏭ self-test — skipped
⏭ native · ${{ matrix.platform }} — skipped
⏭ hygiene — skipped
report 20s setup-node · 6s
🔭 Full CI trace for this commit

One OpenTelemetry trace of CI and Pip-Boy for adfc1cf: every job and step, with the sizes above attached. Run after CI finishes.

pnpm install --frozen-lockfile --filter 'pipboy...'
pnpm --filter pipboy pipboy trace --sha adfc1cfd57905c0e8ca86c6295b62a7bc742af9d

Add --otlp <url> to send it to any OTLP/HTTP collector.

Agent instruction: From a rivet-dev/agentos checkout, run the commands above, then read the trace file the last command prints. List the slowest jobs and steps and explain where CI time went.

The undici stream shim's finished() polled web streams with a ref'd 0 ms timer until they closed. An unread fetch body never closes, so the timer kept the guest process alive and busy. Watch the web-streams-polyfill state transition instead, so finished() holds no event-loop reference, matching Node's eos.
@eersnington
eersnington force-pushed the fix/fetch-unread-body-liveness branch from 2f6d6b3 to adfc1cf Compare October 21, 2026 17:19
@eersnington
eersnington merged commit 3758f30 into main Oct 21, 2026
15 checks passed
@eersnington
eersnington deleted the fix/fetch-unread-body-liveness branch October 21, 2026 19:22
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