Skip to content

fix(sidecar): release kernel socket slots when guest sockets close#196

Merged
NathanFlurry merged 1 commit into
mainfrom
stack/fix-sidecar-release-kernel-socket-slots-when-guest-sockets-close-pympklxu
Jul 2, 2026
Merged

fix(sidecar): release kernel socket slots when guest sockets close#196
NathanFlurry merged 1 commit into
mainfrom
stack/fix-sidecar-release-kernel-socket-slots-when-guest-sockets-close-pympklxu

Conversation

@NathanFlurry

Copy link
Copy Markdown
Member

Closed guest loopback sockets never released their kernel socket-table slots
until process exit (measured: vm_sockets highWater 81 for a workload whose
true concurrency is ~9), so connection-churning guests hit EAGAIN 'maximum
socket count reached' at ~250 cumulative sockets.

  • Bridge: natural FIN close finalization now releases the sidecar/kernel
    handle (idempotent, once), deferred until JS readable buffers drain so
    buffered data is never dropped.
  • Sidecar: net.poll close handling closes the underlying TCP/Unix handle when
    removing map entries; explicit close paths funnel through an idempotent
    kernel close (ENOENT tolerated); the TLS-mode close path no longer skips
    kernel close for kernel-backed sockets.
  • Guest fetch() now uses a bounded per-call undici dispatcher instead of the
    process singleton whose pooled clients went stale against released sockets
    and hung (also fixes a pre-existing hang: repeated fetch over a kept-alive
    loopback connection). Revisit pooling when host->guest socket event push
    (perf: push socket events host→guest instead of guest wait=0 polling #178) lands.
  • Regression test: guest churns 3x max_sockets connections with closes.

Full net family at 30 iterations passes (previously EAGAIN at tcp_concurrent_4):
fetch 2.59ms, tcp_echo 3.57ms, tcp_concurrent_4 4.91ms guest p50; leak probe
highWater 81 -> 17 with depth returning to 0.

Closed guest loopback sockets never released their kernel socket-table slots
until process exit (measured: vm_sockets highWater 81 for a workload whose
true concurrency is ~9), so connection-churning guests hit EAGAIN 'maximum
socket count reached' at ~250 cumulative sockets.

- Bridge: natural FIN close finalization now releases the sidecar/kernel
  handle (idempotent, once), deferred until JS readable buffers drain so
  buffered data is never dropped.
- Sidecar: net.poll close handling closes the underlying TCP/Unix handle when
  removing map entries; explicit close paths funnel through an idempotent
  kernel close (ENOENT tolerated); the TLS-mode close path no longer skips
  kernel close for kernel-backed sockets.
- Guest fetch() now uses a bounded per-call undici dispatcher instead of the
  process singleton whose pooled clients went stale against released sockets
  and hung (also fixes a pre-existing hang: repeated fetch over a kept-alive
  loopback connection). Revisit pooling when host->guest socket event push
  (#178) lands.
- Regression test: guest churns 3x max_sockets connections with closes.

Full net family at 30 iterations passes (previously EAGAIN at tcp_concurrent_4):
fetch 2.59ms, tcp_echo 3.57ms, tcp_concurrent_4 4.91ms guest p50; leak probe
highWater 81 -> 17 with depth returning to 0.
@NathanFlurry

NathanFlurry commented Jul 2, 2026

Copy link
Copy Markdown
Member Author

Stack for rivet-dev/secure-exec

Get stack: forklift get 196
Push local edits: forklift submit
Merge when ready: forklift merge 196

@railway-app railway-app Bot temporarily deployed to secure-exec / secure-exec-pr-196 July 2, 2026 10:01 Destroyed
@NathanFlurry NathanFlurry merged commit 4f470c6 into main Jul 2, 2026
2 of 3 checks passed
@NathanFlurry NathanFlurry deleted the stack/fix-sidecar-release-kernel-socket-slots-when-guest-sockets-close-pympklxu branch July 2, 2026 10:03
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