fix(agentdb): cache prepared statements to plug sql.js leak#144
Merged
Conversation
Both sql.js wrappers in db-fallback.ts (SqlJsDatabase and wrapExistingSqlJsDatabase) tracked every prepare() call in activeStatements and only removed entries on finalize() or error. The idiomatic better-sqlite3 pattern db.prepare(sql).run(...) — which relies on V8 to GC the handle — leaks unbounded under sql.js because WASM-backed Statement objects need explicit .free(). Production observation (Cloud Run mcp-bridge): ~3 statements/s growth, hit 621 within minutes: [ruflo]⚠️ Detected 562 active SQL statements - possible memory leak [ruflo]⚠️ Detected 612 active SQL statements - possible memory leak [ruflo]⚠️ Detected 621 active SQL statements - possible memory leak Fix: cache wrappers by SQL text. Repeated prepare(sameSql) returns the same wrapper; activeStatements.size is now bounded by the count of distinct SQL strings. Safe under single-threaded JS — bind/step/reset are synchronous so no two run/get/all calls can interleave on a shared stmt. finalize() is now a no-op on cached wrappers (close() owns teardown); auto-free-on-error also evicts from cache so a broken stmt isn't reused. Smoke test (5000 prepare(INSERT).run + 1 prepare(SELECT).get): activeStatements_size: 2 (was 5001 pre-patch) statementCache_size: 2 post_close_active: 0 post_close_cache: 0 Typecheck: clean. Test failures observed in repo are pre-existing (jest stubs in vitest project, hnsw zero-vector edge case) — unrelated to this change. Co-Authored-By: claude-flow <ruv@ruv.net>
sparkling
added a commit
to sparkling/agentic-flow
that referenced
this pull request
May 3, 2026
Upstream commit f31065c: fix(agentdb): cache prepared statements to plug sql.js leak. Relevant despite our RVF-primary path because SQLite is documented fallback per ADR-0110.
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
Both sql.js wrappers in
packages/agentdb/src/db-fallback.tstracked everyprepare()call inactiveStatementsbut only removed entries onfinalize()or error. The idiomatic better-sqlite3 patterndb.prepare(sql).run(...)— which relies on V8 to GC the handle — leaks unbounded under sql.js because WASM-backedStatementobjects need explicit.free().Observed in
mcp-bridgeCloud Run logs (~3 statements/s growth):Fix
Cache wrappers by SQL text. Repeated
prepare(sameSql)returns the same wrapper;activeStatements.sizeis now bounded by the count of distinct SQL strings the application uses.bind/step/resetare synchronous, so no tworun/get/allcalls can interleave on a shared stmt.finalize()is a no-op on cached wrappers;close()owns teardown.Applied identically to both
SqlJsDatabase(line ~94) andwrapExistingSqlJsDatabase(line ~305).Test plan
tsc --noEmitcleandb.prepare('INSERT...').run()+ 1×db.prepare('SELECT').get():Out of scope
mcp-bridgeCloud Run service. The fix won't reach production until consumers pick up a published version.🤖 Generated with claude-flow