fix: indexation inversée non-bloquante — run_in_executor
CI / lint (push) Failing after 7s
CI / test (push) Has been skipped
CI / build (push) Has been skipped
CI / security (push) Successful in 9s

L'étape 'Building inverted index...' au démarrage bloquait l'event loop
asyncio, empêchant le serveur de répondre aux requêtes HTTP (navigation,
refresh) jusqu'à la fin de l'indexation.

- init_inverted_index() exécuté dans ThreadPoolExecutor via run_in_executor
- get_inverted_index() ne fait plus de rebuild auto bloquant
- Le serveur répond immédiatement, même pendant l'indexation
This commit is contained in:
2026-06-04 07:33:50 -04:00
parent 7a4b3d1329
commit 8819d04cf2
3 changed files with 19 additions and 9 deletions
+8
View File
@@ -172,6 +172,14 @@
- [x] **Mise à jour automatique** : quand on clique sur un dossier dans l'arborescence, la page se met à jour
- [x] **Déclenchement** : affiché automatiquement quand un vault spécifique est sélectionné
### ✅ 12. Indexation non-bloquante — FAIT
- **Effort** : 0.5 jour | **Impact** : 🟡
- L'étape "Building inverted index..." au démarrage bloquait l'event loop asyncio, empêchant le serveur de répondre aux requêtes HTTP (navigation, refresh) jusqu'à la fin de l'indexation.
- **Fichiers** : `backend/main.py`, `backend/search.py`
- [x] **`init_inverted_index()` dans `run_in_executor`** : exécuté dans le `ThreadPoolExecutor` au lieu de la boucle asyncio principale
- [x] **`get_inverted_index()` sans rebuild auto** : ne déclenche plus de rebuild bloquant — retourne l'index vide si pas encore prêt (les recherches retournent 0 résultats jusqu'à la fin de l'indexation)
- [x] **Navigation + refresh fonctionnels immédiatement** : le serveur répond aux requêtes HTTP dès le démarrage, même pendant l'indexation
---
## 📋 Backlog (P3/P4 — Long terme)
+5 -2
View File
@@ -573,8 +573,11 @@ async def lifespan(app: FastAPI):
logger.info("Background indexing started")
await build_index(_progress_cb)
# Build inverted index for search (one-time, then incremental)
init_inverted_index()
# Build inverted index in a thread pool to avoid blocking the event loop.
# The inverted index rebuild is CPU-bound (tokenization, indexing) and
# would freeze HTTP responses if run in the async event loop.
loop = asyncio.get_running_loop()
await loop.run_in_executor(_search_executor, init_inverted_index)
# Start file watcher
config = _load_config()
+6 -7
View File
@@ -672,14 +672,13 @@ def init_inverted_index():
def get_inverted_index() -> InvertedIndex:
"""Return the singleton inverted index.
Auto-builds on first call if the index has files but the inverted
index hasn't been built yet (fallback for paths that don't go through
``init_inverted_index()``).
The inverted index is built once at startup in a background thread.
If called before the build completes, returns an empty index (searches
will return no results until the build finishes).
No automatic rebuild — the startup sequence handles the initial build.
Incremental updates are applied via ``update_inverted_index()``.
"""
if _inverted_index.doc_count == 0 and any(
vdata.get("files") for vdata in index.values()
):
_inverted_index.rebuild()
return _inverted_index