fix(personal): run directory indexing off the event loop#5634
Open
StressTestor wants to merge 1 commit into
Open
fix(personal): run directory indexing off the event loop#5634StressTestor wants to merge 1 commit into
StressTestor wants to merge 1 commit into
Conversation
POST /api/personal/add_directory called rag.index_personal_documents inline from an async handler, so the whole indexing job (os.walk, file reads, per-chunk embedding, Chroma inserts) ran on the event loop and every other request queued behind it. Indexing a real directory froze the UI and API for 25+ minutes with no sign of life. Move the blocking section into the threadpool via run_in_threadpool. personal_docs_manager.add_directory stays inside it because its refresh_index() re-extracts text across tracked directories, which is also blocking work. A module-level lock serializes index jobs so the threadpool move does not introduce parallel jobs racing PersonalDocsManager's unsynchronized list mutations and file writes; they previously serialized on the blocked loop, so one-at-a-time is behavior parity.
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
POST /api/personal/add_directoryis anasync defhandler that called the fully synchronousrag.index_personal_documentsinline, so the entire indexing job (os.walk, file reads, per-chunk embedding, Chroma inserts) ran on the event loop. Every other request queued behind it: indexing a real directory froze the UI and API for 25+ minutes with no sign of life (the reporter's users concluded the app crashed).This PR moves the blocking section into the threadpool via
fastapi.concurrency.run_in_threadpool.personal_docs_manager.add_directorystays inside the moved section because it triggersrefresh_index(), which re-extracts text across tracked directories, also blocking work. A module-level lock serializes index jobs: without it the threadpool move would let concurrent requests run parallel jobs that racePersonalDocsManager's unsynchronized list mutations and plainopen('w')file writes. Jobs previously serialized on the blocked loop anyway, so one-at-a-time is behavior parity, minus the freeze.Target branch
dev, notmain.Linked Issue
Fixes #5558
Type of Change
Checklist
devuvicorn app:app+ a local ChromaDB atlocalhost:8100) and verified the change works end-to-end.How to Test
python -m pytest tests/test_add_directory_event_loop.py: 4 tests. The thread-identity test asserts indexing and bookkeeping run off the event loop thread (fails ondev, where both run on it); the serialization test asserts concurrent requests never run parallel index jobs; the other two pin response shape and the error path.data/personal_docs/bigvault/with 150 markdown files,POST /api/personal/add_directory, and while the job is running, time aGET /api/personalfrom a second terminal.dev: the GET takes 3.2s, because it queues behind the whole remaining index job (with the reporter's 25-minute job, that GET waits minutes).indexed_count: 150, failed_count: 0.Also ran: full
python -m pytest(4674 passed, 3 skipped; the 5 failures are the docker-socket tests, which fail identically on cleandevon this machine, macOS with no docker socket) andpython -m compileall app.py core routes src services scripts tests.Scope notes
POST /reloadorDELETE /remove_directorymid-job could race the indexing thread's bookkeeping, a window that could not occur before because the blocked loop prevented any dispatch. Admin-only and narrow; the clean fix is a lock insidePersonalDocsManageritself, which i kept out of this PR to keep the diff reviewable. Can follow up.