From ded3c541ae6a42ec33bb510902655cc7b5a2d2b4 Mon Sep 17 00:00:00 2001 From: Jpumpkin1223 Date: Sat, 18 Apr 2026 20:33:36 +0900 Subject: [PATCH] fix: remove outer transaction wrapper in sync to prevent PGlite deadlock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When syncing >10 files, sync.ts wrapped all importFile() calls inside a single engine.transaction(). However, importFile() opens its own inner transaction on the same connection, and PGlite does not support nested transactions — the event loop hangs indefinitely. Remove the conditional outer transaction wrapper. Each importFile() call is already individually atomic, so no outer wrapper is required. Fixes: gbrain sync hanging forever when more than 10 files are changed. --- src/commands/sync.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/commands/sync.ts b/src/commands/sync.ts index 7034ea0d..543fa93a 100644 --- a/src/commands/sync.ts +++ b/src/commands/sync.ts @@ -203,8 +203,12 @@ export async function performSync(engine: BrainEngine, opts: SyncOpts): Promise< pagesAffected.push(newSlug); } - // Process adds and modifies - const useTransaction = (filtered.added.length + filtered.modified.length) > 10; + // Process adds and modifies. + // NOTE: importFile manages its own transaction internally. Wrapping all + // importFile() calls in an outer engine.transaction() causes nested + // db.transaction() calls that deadlock PGlite's event loop indefinitely + // (reproducible with >10 files in a single sync). Each file import is + // individually atomic — no outer wrapper needed. const processAddsModifies = async () => { for (const path of [...filtered.added, ...filtered.modified]) { const filePath = join(repoPath, path); @@ -222,11 +226,7 @@ export async function performSync(engine: BrainEngine, opts: SyncOpts): Promise< } }; - if (useTransaction) { - await engine.transaction(async () => { await processAddsModifies(); }); - } else { - await processAddsModifies(); - } + await processAddsModifies(); const elapsed = Date.now() - start;