fix(ipc): connect reliability for spawned wsdb/bb-avm-sim services - #25073
Merged
Conversation
fcarreiro
approved these changes
Aug 10, 2026
…db/bb-avm-sim services Hardens the generated IPC packages' spawn-and-connect path against the failure family behind #24802, and makes bb-avm-sim process failures invisible to everything above the AVM pool. Servers listen before heavy init: aztec-wsdb creates its socket before WorldState construction and bb-avm-sim before its upstream wsdb/CDB connects, so clients connect into the accept backlog immediately and the connect backstop only covers exec + linking + reaching listen(). bb-avm-sim installs SIGUSR1 and lifecycle handlers (incl. parent-death monitoring) before the socket is reachable; upstream connect budget 5s -> 60s. ipc-runtime gains SpawnedProcessBackend, extracted from the codegen template: liveness-based connect raced against child death, kill-on-expiry backstop, log capture (async fs throughout — sync fs here would stall the event loop on exactly the degraded machines this path runs on), SIGTERM -> SIGKILL teardown, and opt-in lazy respawn (next call after a death gets a fresh process; stable ipc path; no eager crash-loop). Errors are typed (IpcTransportError, IpcProcessExitedError, IpcSpawnError) with a retry flag distinguishing process death from configuration errors; call failures that race the child's exit event are attributed to the death after a short grace. The generated package shrinks to binary resolution + backend config and passes through a respawn option; the call surface gains nothing. The AVM pool spawns services with respawn enabled and is the only interpreter of the retry flag — callers keep exact pre-IPC semantics (result, tx failure, or their own deadline). Environmental spawn failures retry indefinitely on a flat 1s cadence (no backoff: sequencers live on ~6s slots), bounded by the caller's abort signal, which threads through checkout, the spawn-retry loop, and full-pool waits. A simulation whose process dies is re-issued once; a second death is attributed to the input so a simulator-crashing tx is evicted instead of retried forever. Cancellation escalates SIGUSR1 -> (5s) -> SIGKILL, reclaiming the pool slot from a wedged simulation. Configuration errors surface fatally at the boot-time prewarm. wsdb keeps fail-fast semantics: a respawned wsdb would lose all forks and uncommitted state. New tests: SpawnedProcessBackend unit tests (script-based fake servers), echo ts_package reliability tests (slow-listen, die-before-listen, wedged-then-killed, missing-binary classification, respawn), AVM pool tests (indefinite abort-aware spawn retry, config fast-fail, re-issue-once, input attribution), and wsdb/avm server compile + startup-order checks.
charlielye
force-pushed
the
cl/ipc-connect-reliability
branch
from
August 10, 2026 10:43
24c4c44 to
20b3267
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Hardens the spawn-and-connect path used by the generated IPC packages (
@aztec/wsdb,@aztec/bb-avm-sim), and makes bb-avm-sim failures non-fatal to the prover. Reviewing this stack against the bb socket incident fixed in #24802 showed the specific shared-budget bug from that incident does not reproduce here, but the same failure family was present — in the connect path, and in how environmental failures were classified downstream.Commit 1 — connect reliability
Servers listen before heavy init.
aztec-wsdbpreviously constructed its entireWorldState(LMDB open, genesis prefill) beforelisten(), andbb-avm-simconnected to its upstream wsdb/CDB servers before creating its own socket — so the client-side connect timeout was a bet on how fast a loaded machine can do real, unbounded work. Both servers now listen first: clients connect straight into the kernel accept backlog and first requests wait in the socket buffer until the reactor starts, so the connect backstop only ever covers exec + linking + reachinglisten(). A server that dies during init surfaces its real exit cause instead of a spurious connect timeout.bb-avm-simalso installs its SIGUSR1 cancellation handler before the socket is reachable (the default disposition is process termination) and its lifecycle handlers — including parent-death monitoring — before the potentially-long upstream waits, whose budget goes from a hard-coded 5s to a 60s backstop.Client-side liveness-based connect. The connect wait is raced against child death (a dead server fails immediately with its exit code/signal); the backstop (60s) is purely a broken-process detector and now kills the wedged child instead of orphaning it (an orphaned wsdb holds LMDB locks on its data dir, poisoning any respawn). Every spawn-failure path reaps the child, unlinks the ipc path, and points at the child's captured log. Hard connect errors (EACCES etc.) fail immediately instead of being retried until the deadline;
EAGAIN(momentarily full accept backlog under simultaneous pool spawns) is retryable.destroy()escalates SIGTERM → SIGKILL after 5s.One behavioural consequence: spawn resolving no longer implies the server finished initializing. All consumers issue their first call immediately after spawn and simply block until init completes; an init failure surfaces on that first call with the child's exit code and log path.
Commits 2+3 — the backend owns process lifecycle; callers keep pre-IPC semantics
Previously a bb-avm-sim spawn failure or crash was fatal to the prover: the error was rewrapped into
SimulationError, the tx reported failed, the checkpoint prover failed, and the session manager blocks that epoch until a prune replaces the failed prover — i.e. forever (hasFailedProver). The pool also never evicted dead processes, so one crash permanently poisoned a slot; and the sequencer drops failed txs from P2P, so environmental failures evicted innocent txs.The design principle: process lifecycle belongs to the layer that owns the process, and never appears above it. Pre-IPC (in-process NAPI), callers could assume every failure was an actual tx failure, with the processor's deadline as the only environmental bound; that contract is preserved exactly.
SpawnedProcessBackend, extracted from the codegen template (which embedded ~200 lines of process machinery per generated package, untestable except through them). It owns spawn, connect, death detection, teardown — and opt-in lazy respawn: the nextcall()after a death transparently gets a fresh process (one shared respawn attempt, stable ipc path, lazy-only so a crashing binary can't respawn-loop unprompted). Errors are typed —IpcTransportError,IpcProcessExitedError,IpcSpawnError— and carry aretryflag distinguishing process death from configuration errors. Call failures that race the child'sexitevent (the socket breaks first) are attributed to the death after a short grace, so deaths are never misreported as bare transport errors.respawn?: booleanspawn option. The call surface gains nothing.respawn: true(each simulation is self-contained; state is routed via WSDB/CDB by fork id) and is the only interpreter of the backend's error flags. It absorbs environmental trouble outright: spawn failures retry indefinitely on a flat 1s cadence — no backoff: sequencers live on ~6s slots, so sleeping longer after a failure costs whole blocks while the machine may have recovered, and slow attempts self-pace inside the backend connect backstop, bounded by the caller's own deadline — the abort signal threads through checkout, the spawn-retry loop, and full-pool waits, all of which stop promptly on abort. For the sequencer that bound is the slot deadline (execWithSignal); for the prover, the epoch deadline — meaning a checkpoint prover riding out a load spike just waits (loudly logged) and the epoch fails only at its true deadline, rather than being permanently poisoned after a fixed budget. Configuration errors (missing binary) still fail fast, at the boot-time prewarm.wsdb deliberately keeps fail-fast semantics: a respawned wsdb loses all forks, checkpoints, and uncommitted state, so clients holding forkIds would silently read wrong state; its death remains a node-level event, surfaced with typed cause and log path.
Deliberately out of scope: SHM readiness/call timeouts (shm has no readiness handshake; nothing deploys shm-wsdb today — it's exercised only by a parameterized world-state test).
Tests
ipc-runtime: unit tests forSpawnedProcessBackendagainst script-based fake servers — death → typed exit error, lazy respawn gets a fresh pid, missing binary flagged as configuration, dies-before-listen fails promptly with the exit code, wedged process killed at the backstop, destroy during a pending respawn leaks nothing.ts_packagereliability tests (run in ipc-codegen CI, uds + shm): slow-to-listen, dies-before-listen, wedged-then-killed (fails on the pre-fix(ipc): connect reliability for spawned wsdb/bb-avm-sim services #25073 code by construction), missing-binary classification, death-without-respawn, respawn-recreates-process.public_tx_simulatorsuite green.aztec-wsdb/bb-avm-simcompile, a manual wsdb run showslistening onbeforeCreating WorldStatewith a clean socket unlink on failed init, both generated packages rebuilt, full yarn-project TS build passes.