Reload knowledge_base.json on sibling uwsgi workers after a rebuild - #135
Merged
Conversation
/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
approved these changes
Sep 7, 2026
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
app.pyrunsuwsgi --lazy-apps --processes 2, so each worker process has its ownRAGSysteminstance./trigger-rebuildrunsrun_rebuild()in whichever worker got the request; that worker'srag_system.rebuild()rewrites the two embedding.npyfiles and its ownself.knowledge_base, but the sibling worker never gets the call.retrieve()is wrapped incache_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, neverself.knowledge_base, andcache_checknever trackedknowledge_base.json's mtime at all. So a sibling worker ends up serving fresh embeddings against a staleknowledge_baselist. Sincecompute_document_scoreslooks upabout/text/pathby list index againstself.knowledge_base, a rebuild that changes the doc count leaves the sibling returning content for the wrong document, not just outdated content.Changes
knowledge_base_timestampalongside the two embedding timestamps (set in__init__andrebuild_embeddings).cache_checknow also comparesknowledge_base.json's mtime;_reload_cachenow also reloadsself.knowledge_basefrom disk, under the existingself._update_lock._reload_cachenever tookself._update_lockat all.cache_check's error handler calledself.rebuild_embeddings()with no argument, though the method requires aknowledge_basearg - this would have raisedTypeErrorif that path were ever exercised.get_knowledge_base.py's final write ofknowledge_base.jsonis 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.pyisn't wired into CI (build.yamlonly runsruff), and has pre-existing, unrelated bugs that predate this change (e.g.setUpClasscallsrebuild_embeddings()with no argument, and a self-referential real/fake swap intest_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 plusruff check/ruff format --check(both green, pinned to the CI version 0.16.5).Fixes #110
🤖 Generated with Claude Code