Skip to content

fix(pxe): stop block synchronizer on PXE shutdown#22604

Merged
benesjan merged 1 commit into
merge-train/fairiesfrom
jan/f-339-pxe-stop-release-resources
Apr 17, 2026
Merged

fix(pxe): stop block synchronizer on PXE shutdown#22604
benesjan merged 1 commit into
merge-train/fairiesfrom
jan/f-339-pxe-stop-release-resources

Conversation

@benesjan

@benesjan benesjan commented Apr 16, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes https://linear.app/aztec-labs/issue/F-339

The issue reported three resource leaks in PXE.stop():

  1. L2BlockStream — active RunningPromise with timers: The issue assumed the block stream runs in polling mode (start()), but in the PXE context blockStream.start() is never called — the stream is only used in manual sync mode via blockStream.sync(). So there are no active timers or InterruptibleSleep handles keeping the event loop alive. That said, calling blockStream.stop() is still good defensive practice in case the usage mode changes.

  2. LMDB store — open file descriptors: PXE.stop() already calls this.db.close(), so this part was already fixed at some point after the issue was filed.

  3. HTTP keep-alive sockets from createAztecNodeClient: Node's built-in fetch (undici) uses HTTP keep-alive by default — after a request completes, the underlying TCP socket stays open in case another request comes to the same host. These idle sockets register as active handles on the event loop, preventing process.exit() from happening naturally. Fixing this would require either using a custom undici Agent/Pool with a close() method, or setting keepalive: false (which hurts performance). In practice this doesn't matter: the sockets time out on their own after a few seconds, and for long-running services (the main use case) the process stays up anyway. Only relevant if you need the process to exit immediately after stop() without calling process.exit(0).

What this PR actually fixes: BlockSynchronizer had no stop() method at all. If PXE.stop() were called while a sync was in progress, the ongoing sync could race against db.close(). While the job queue draining makes this unlikely in practice, adding an explicit stop() is the right defensive pattern and matches what ServerWorldStateSynchronizer already does.

Changes

  • Adds a stop() method to BlockSynchronizer that awaits any in-progress sync, then stops the block stream
  • Calls blockStateSynchronizer.stop() in PXE.stop() between draining the job queue and closing the DB
  • Shutdown order: job queue drains (no new syncs) → synchronizer stops (waits for in-flight sync) → DB closes

`PXE.stop()` did not stop the `BlockSynchronizer`, which could lead to
a race where an in-progress sync accesses the DB after it's been closed.
Add a `stop()` method to `BlockSynchronizer` that waits for any ongoing
sync and stops the block stream, and call it from `PXE.stop()` before
closing the DB.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@benesjan benesjan merged commit 2a5be6d into merge-train/fairies Apr 17, 2026
29 of 33 checks passed
@benesjan benesjan deleted the jan/f-339-pxe-stop-release-resources branch April 17, 2026 07:47
@AztecBot

Copy link
Copy Markdown
Collaborator

❌ Failed to cherry-pick to v4-next due to conflicts. (🤖) View backport run.

AztecBot pushed a commit that referenced this pull request Apr 17, 2026
Cherry-picked 96ffbf3 with unresolved conflicts in yarn-project/pxe/src/pxe.ts.
This commit intentionally preserves the conflict markers so reviewers can see
the original diff.

Co-Authored-By: benesjan <janbenes1234@gmail.com>
github-merge-queue Bot pushed a commit that referenced this pull request Apr 17, 2026
BEGIN_COMMIT_OVERRIDE
fix(pxe): stop block synchronizer on PXE shutdown (#22604)
fix(aztec): respect TEST_ACCOUNTS env var in local network mode (#22600)
fix: check all aztec-nr dependency tags, not just aztec (#22483)
fix: reuse anchor block in kernel oracle (#22631)
refactor: unify contract compilation pipeline via bb aztec_process
(#22590)
fix(pxe): queue registerSender wipe to avoid racing with in-flight jobs
(#22623)
fix(pxe): bounds-check PropertySelector in pick_notes (#22614)
fix(pxe): guard private event store rollback against in-flight jobs
(#22615)
refactor(pxe): rename sideEffectCounter to initialSideEffectCounter
(#22599)
fix(pxe): correct stale authwitness comment and inverted tagging error
(#22537)
fix(aztec-nr): range-check auth witness fields before byte cast (#22624)
fix(pxe): serialize block stream event handling to prevent race
conditions (#22635)
fix(pxe): throw error on origin/contract address mismatch in simulation
(#22637)
END_COMMIT_OVERRIDE
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants