fix(engine): move bootstrap file I/O off the event loop#403
Merged
Conversation
readFileSegment, readLastJsonlEntryBeforeOffset, and the statSync calls in bootstrap() / refreshBootstrapState() all used synchronous Node.js fs APIs. On multi-MB session JSONL files the backward scan in readLastJsonlEntryBeforeOffset could block the event loop for minutes, freezing every gateway session, the Control UI, CLI, and WebSocket connections. Convert those functions to fs/promises (open / FileHandle.read / FileHandle.stat / stat). readAppendedLeafPathMessages becomes async transitively. The backward scan now also only reads a new chunk when the current carry has no more newlines to peel, instead of re-reading on every iteration (which both wasted I/O and amplified the implicit O(n^2) prepended-carry pattern). The bootstrap append-only fast path additionally short-circuits before the expensive backward scan when latestDbHash !== lastProcessedEntryHash. That is the common case during active sessions (the DB frontier advances past the checkpoint between bootstraps), and the matcher can never find a matching tail entry in that state, so we skip straight to the async full-read slow path. Tests in bootstrap-message-only.test.ts are updated to await the now-async function; full vitest suite (695 tests, 40 files) stays green. Co-Authored-By: WoCha <wocha@jetd.one> via Claude Code
Contributor
|
Thank you! |
This was referenced Apr 11, 2026
Merged
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.
Summary
readFileSegment,readLastJsonlEntryBeforeOffset, and thestatSynccalls inbootstrap()/refreshBootstrapState()tofs/promises, so a multi-MB session JSONL can no longer block the Node.js event loop for minutes during the append-only bootstrap path (freezing every gateway session, Control UI, CLI, and WebSocket connection).readLastJsonlEntryBeforeOffset, only read a new chunk when the current carry has no more newlines to peel. The original re-read a chunk on every iteration even while still processing existing lines, which wasted I/O and amplified the implicit O(n^2) prepended-carry pattern.latestDbHash !== bootstrapState.lastProcessedEntryHash. That is the common case during active sessions — the DB frontier advances past the checkpoint between bootstraps, and the matcher can never find a matching tail entry in that state, so we skip straight to the async full-read slow path.A patch-level changeset is included per
RELEASING.md.Test plan
npm test— full vitest suite passes (695 tests, 40 files) on this branchnpx tsc --noEmit— no new type errors introduced in touched files (unrelated pre-existing errors elsewhere are unchanged)bootstrap-message-only.test.tsupdated toawaitthe now-asyncreadLastJsonlEntryBeforeOffset; all 12 cases still passsetTimeoutcallback fires within ~100 ms while bootstrap is reconcilingCo-Authored-By: WoCha wocha@jetd.one via Claude Code