From f9e99701a0ef3f1b1dd743ba8fc37f116bb8124e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C4=93sa=20AI?= Date: Fri, 24 Apr 2026 15:41:38 -0700 Subject: [PATCH 1/2] fix(memory-core): yield to event loop during seedEmbeddingCache iterate R2.A.2. The .iterate()-based seed (R2.A v1, a315280) prevents the V8 heap OOM but the iterate loop still runs synchronously for ~117s on a 435K-row embedding_cache. wip-healthcheck SIGKILLs the gateway after its 30s probe timeout fails. No FATAL ERROR, no Abort trap. Patch: convert seedEmbeddingCache to async, yield to the event loop every 1000 rows via setImmediate. Keeps memory bounded; preserves the streaming behavior; restores /health responsiveness during the seed. The only caller is inside an existing async arrow wrapping runMemoryAtomicReindex's build callback. Adding await is a one-line change. Validation: - pnpm tsgo:prod: green - pnpm test extensions/memory-core: 512 passed, 3 skipped, 0 failed Scope: does not soften wip-healthcheck (separate guardrail per Parker direction). Does not address secondary listChunks path (R2.A.3). --- .../memory-core/src/memory/manager-sync-ops.ts | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/extensions/memory-core/src/memory/manager-sync-ops.ts b/extensions/memory-core/src/memory/manager-sync-ops.ts index 1b82f0c8f770..5e57f1c13bc8 100644 --- a/extensions/memory-core/src/memory/manager-sync-ops.ts +++ b/extensions/memory-core/src/memory/manager-sync-ops.ts @@ -1,3 +1,8 @@ +// (lint suppression removed; oxlint state varies — rule did not fire on retry) +// ^ pre-existing oxlint type-resolver false positive: oxlint resolves SessionFileEntry +// (line 190) and EmbeddingProvider (line 129) as `error/any` even though tsgo:prod +// resolves them cleanly. Filed as separate cleanup; suppressed file-level here so +// R2.A.2 (and prior R2.A v1) can land without unrelated lint debt blocking. import { randomUUID } from "node:crypto"; import fsSync from "node:fs"; import fs from "node:fs/promises"; @@ -295,7 +300,7 @@ export abstract class MemoryManagerSyncOps { return openMemoryDatabaseAtPath(dbPath, this.settings.store.vector.enabled); } - private seedEmbeddingCache(sourceDb: DatabaseSync): void { + private async seedEmbeddingCache(sourceDb: DatabaseSync): Promise { if (!this.cache.enabled) { return; } @@ -323,6 +328,9 @@ export abstract class MemoryManagerSyncOps { updated_at=excluded.updated_at`, ); this.db.exec("BEGIN"); + // Yield to event loop every N rows so HTTP /health probes stay responsive. + const SEED_EMBEDDING_YIELD_EVERY = 1000; + let rowCount = 0; for (const row of rows) { insert.run( row.provider, @@ -333,6 +341,12 @@ export abstract class MemoryManagerSyncOps { row.dims, row.updated_at, ); + rowCount += 1; + if (rowCount % SEED_EMBEDDING_YIELD_EVERY === 0) { + await new Promise((resolve) => { + setImmediate(resolve); + }); + } } this.db.exec("COMMIT"); } catch (err) { @@ -1160,7 +1174,7 @@ export abstract class MemoryManagerSyncOps { targetPath: dbPath, tempPath: tempDbPath, build: async () => { - this.seedEmbeddingCache(originalDb); + await this.seedEmbeddingCache(originalDb); const shouldSyncMemory = this.sources.has("memory"); const shouldSyncSessions = this.shouldSyncSessions( { reason: params.reason, force: params.force }, From 675e54dbf1c76358ed3d23ea9900063d17c08b85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C4=93sa=20AI?= Date: Fri, 24 Apr 2026 15:46:54 -0700 Subject: [PATCH 2/2] fix(memory-core): remove misleading lint-comment churn from R2.A.2 Revert the top-of-file lint-suppression comments accidentally landed in the previous commit (f9e99701). They were added to work around an oxlint resolver false positive that turned out to be transient state, not a real lint failure. Production code shouldn't carry misleading explanations for problems that didn't actually persist. Net diff of this branch vs base is now just the seedEmbeddingCache yield patch: function -> async, setImmediate every 1000 rows, caller await. No lint comments, no file-level disables. --- extensions/memory-core/src/memory/manager-sync-ops.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/extensions/memory-core/src/memory/manager-sync-ops.ts b/extensions/memory-core/src/memory/manager-sync-ops.ts index 5e57f1c13bc8..ba6f6951a1ba 100644 --- a/extensions/memory-core/src/memory/manager-sync-ops.ts +++ b/extensions/memory-core/src/memory/manager-sync-ops.ts @@ -1,8 +1,3 @@ -// (lint suppression removed; oxlint state varies — rule did not fire on retry) -// ^ pre-existing oxlint type-resolver false positive: oxlint resolves SessionFileEntry -// (line 190) and EmbeddingProvider (line 129) as `error/any` even though tsgo:prod -// resolves them cleanly. Filed as separate cleanup; suppressed file-level here so -// R2.A.2 (and prior R2.A v1) can land without unrelated lint debt blocking. import { randomUUID } from "node:crypto"; import fsSync from "node:fs"; import fs from "node:fs/promises";