Skip to content

Reload knowledge_base.json on sibling uwsgi workers after a rebuild - #135

Merged
lionello merged 1 commit into
mainfrom
fix/reload-stale-knowledge-base-cache
Sep 7, 2026
Merged

Reload knowledge_base.json on sibling uwsgi workers after a rebuild#135
lionello merged 1 commit into
mainfrom
fix/reload-stale-knowledge-base-cache

Conversation

@defangdevs

Copy link
Copy Markdown
Contributor

Summary

app.py runs uwsgi --lazy-apps --processes 2, so each worker process has its own RAGSystem instance. /trigger-rebuild runs run_rebuild() in whichever worker got the request; that worker's rag_system.rebuild() rewrites the two embedding .npy files and its own self.knowledge_base, but the sibling worker never gets the call.

retrieve() is wrapped in cache_check, which already compared the embedding files' mtimes and called _reload_cache() on a sibling when they changed - but _reload_cache() only reloaded the embedding arrays, never self.knowledge_base, and cache_check never tracked knowledge_base.json's mtime at all. So a sibling worker ends up serving fresh embeddings against a stale knowledge_base list. Since compute_document_scores looks up about/text/path by list index against self.knowledge_base, a rebuild that changes the doc count leaves the sibling returning content for the wrong document, not just outdated content.

Changes

  • Track knowledge_base_timestamp alongside the two embedding timestamps (set in __init__ and rebuild_embeddings).
  • cache_check now also compares knowledge_base.json's mtime; _reload_cache now also reloads self.knowledge_base from disk, under the existing self._update_lock.
  • Two adjacent bugs fixed in the same code path:
    • _reload_cache never took self._update_lock at all.
    • cache_check's error handler called self.rebuild_embeddings() with no argument, though the method requires a knowledge_base arg - this would have raised TypeError if that path were ever exercised.
  • get_knowledge_base.py's final write of knowledge_base.json is now atomic (atomicwrites, already a project dependency), since a reader now keys off this file's mtime and could otherwise observe a half-written file mid-rebuild.

No public behavior/API change - this only fixes cross-process cache consistency.

Note on tests

app/test_rag_system.py isn't wired into CI (build.yaml only runs ruff), and has pre-existing, unrelated bugs that predate this change (e.g. setUpClass calls rebuild_embeddings() with no argument, and a self-referential real/fake swap in test_cache_check_rebuild_embeddings_on_error) that make the whole suite error out before it reaches any assertions. I didn't fix those here to keep this PR scoped to the issue; verified this change by manual review plus ruff check/ruff format --check (both green, pinned to the CI version 0.16.5).

Fixes #110

🤖 Generated with Claude Code

/trigger-rebuild only runs in the uwsgi worker that received the
request. The cache_check decorator already reloaded the two embedding
.npy files in sibling workers when their mtimes changed, but never
reloaded knowledge_base.json itself - so a sibling served fresh
embeddings against a stale in-memory knowledge_base list, which can
return the wrong "about"/"text"/"path" for a doc index if the
knowledge base's size changed.

Track knowledge_base.json's mtime alongside the embedding files' and
reload it in _reload_cache under the existing update lock. Also fixes
two bugs found in the same code path: _reload_cache never took the
lock, and the cache_check error handler called rebuild_embeddings()
with no argument even though it requires one. Finally, make
get_knowledge_base.py's write of knowledge_base.json atomic, since a
reader now keys off this file's mtime and could otherwise observe a
half-written file mid-rebuild.

Fixes #110

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@lionello
lionello merged commit 909feb0 into main Sep 7, 2026
6 checks passed
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.

trigger-rebuild leaves outdated kb in memory of sibling processes

2 participants