Skip to content

fix: lock the store's summary cache and cache the MCP graph build (#130) - #139

Merged
CryptoJones merged 1 commit into
mainfrom
fix/130-store-lock-graph-cache
Jul 1, 2026
Merged

fix: lock the store's summary cache and cache the MCP graph build (#130)#139
CryptoJones merged 1 commit into
mainfrom
fix/130-store-lock-graph-cache

Conversation

@CryptoJones

Copy link
Copy Markdown
Owner

Closes #130.

  • Web 500s: the web UI runs sync endpoints on FastAPI's threadpool over a single shared OmiStore, so concurrent list_notes() calls mutated the summary cache while another thread iterated it → RuntimeError: dictionary changed size during iteration under the 5-second poll. The cache is now guarded by a lock.
  • Repeated full-vault parse: the MCP server's five graph tools each rebuilt the whole [[wikilink]] graph per call. The build is now cached, invalidated by a cheap vault signature (note count, total size, newest mtime), so a burst of graph queries costs one parse and any write busts it.

Scope note: the single-client stdio MCP server's sync handlers are deliberately left on the event loop. Blocking there delays only that one client's pings/cancellations (not a crash), and the graph cache removes the pathological repeated-parse cost that was the real harm — an async refactor of the critical server every session depends on is disproportionate risk for the remaining latency.

Test plan

  • New tests: list_notes() hammered from 8 threads raises no dict-resize error; the graph build is cached across 3 graph tools (1 build) and busted by a write (2 builds).
  • Full suite: 722 passed, 1 skipped. ruff + mypy clean.

🤖 Generated with Claude Code

Proudly Made in Nebraska. Go Big Red! 🌽 https://xkcd.com/2347/

The web UI ran sync endpoints on FastAPI's threadpool over a single shared
OmiStore, so concurrent list_notes() calls mutated the summary cache while
another thread iterated it -> "dictionary changed size during iteration" 500s
under the 5s poll. Guard the cache with a lock.

The MCP server's five graph tools each rebuilt the whole [[wikilink]] graph
(a full-vault read+parse) per call; cache the build, invalidated by a cheap
vault signature (count, size, newest mtime), so a burst of graph queries costs
one parse and any write busts it.

(The single-client stdio server's sync handlers are left on the event loop:
blocking there delays only that one client's pings, not a crash, and the graph
cache removes the pathological repeated-parse cost — an async refactor of the
critical server is disproportionate risk for the remaining latency.)

Closes #130.

Co-Authored-By: Claude Fable 5 <[email protected]>
@CryptoJones
CryptoJones merged commit 7d9ab3b into main Jul 1, 2026
14 checks passed
@CryptoJones
CryptoJones deleted the fix/130-store-lock-graph-cache branch July 1, 2026 23:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

MCP server + web: run vault I/O off the event loop and lock the shared store

1 participant