feat(status): add /health aggregate endpoint and 10s TTL cache on /stats
This commit is contained in:
@@ -1,32 +1,53 @@
|
||||
"""Define API routes for status."""
|
||||
|
||||
import time
|
||||
from typing import Any
|
||||
|
||||
from fastapi import APIRouter
|
||||
|
||||
from app.config.settings import settings
|
||||
from app.shared.bootstrap import get_document_query_service, get_vector_index
|
||||
# Keep route handlers close to their transport-layer wiring for easier auditing.
|
||||
|
||||
from app.shared.bootstrap import (
|
||||
get_bm25_retriever,
|
||||
get_binary_store,
|
||||
get_conversation_store,
|
||||
get_document_query_service,
|
||||
get_vector_index,
|
||||
)
|
||||
|
||||
router = APIRouter(prefix="/status", tags=["系统状态"])
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Simple TTL cache for /stats (avoids O(N) doc scan on every request)
|
||||
# ---------------------------------------------------------------------------
|
||||
_stats_cache: dict[str, Any] = {}
|
||||
_stats_cache_time: float = 0.0
|
||||
_STATS_TTL_SECONDS: float = 10.0
|
||||
|
||||
|
||||
@router.get("/stats")
|
||||
async def get_stats():
|
||||
"""Return stats."""
|
||||
"""Return document statistics (cached for 10 s)."""
|
||||
global _stats_cache, _stats_cache_time
|
||||
now = time.time()
|
||||
if _stats_cache and (now - _stats_cache_time) < _STATS_TTL_SECONDS:
|
||||
return _stats_cache
|
||||
|
||||
documents = get_document_query_service().list_documents()
|
||||
indexed = sum(1 for item in documents if item.status.value == "indexed")
|
||||
failed = sum(1 for item in documents if item.status.value == "failed")
|
||||
return {
|
||||
indexed = sum(1 for d in documents if d.status.value == "indexed")
|
||||
failed = sum(1 for d in documents if d.status.value == "failed")
|
||||
_stats_cache = {
|
||||
"documents_total": len(documents),
|
||||
"documents_indexed": indexed,
|
||||
"documents_failed": failed,
|
||||
"chunks_total": sum(item.chunk_count for item in documents),
|
||||
"chunks_total": sum(d.chunk_count for d in documents),
|
||||
}
|
||||
_stats_cache_time = now
|
||||
return _stats_cache
|
||||
|
||||
|
||||
@router.get("/config")
|
||||
async def get_config():
|
||||
"""Return config."""
|
||||
"""Return system configuration."""
|
||||
return {
|
||||
"embedding_model": settings.embedding_model,
|
||||
"embedding_dim": settings.embedding_dim,
|
||||
@@ -44,5 +65,49 @@ async def get_config():
|
||||
|
||||
@router.get("/milvus/health")
|
||||
async def milvus_health():
|
||||
"""Handle milvus health."""
|
||||
"""Return Milvus health (kept for backwards compat)."""
|
||||
return get_vector_index().health()
|
||||
|
||||
|
||||
@router.get("/health")
|
||||
async def get_health():
|
||||
"""Return aggregate health of all backend services."""
|
||||
# --- Milvus ---
|
||||
try:
|
||||
milvus_info = get_vector_index().health()
|
||||
milvus_status = "ok" if milvus_info.get("connected") else "error"
|
||||
except Exception as exc: # noqa: BLE001
|
||||
milvus_info = {}
|
||||
milvus_status = "error"
|
||||
milvus_info["error"] = str(exc)
|
||||
|
||||
# --- MinIO ---
|
||||
try:
|
||||
minio_connected = get_binary_store().client.connected
|
||||
minio_status = "ok" if minio_connected else "error"
|
||||
except Exception: # noqa: BLE001
|
||||
minio_status = "error"
|
||||
minio_connected = False
|
||||
|
||||
# --- BM25 ---
|
||||
bm25 = get_bm25_retriever()
|
||||
|
||||
# --- Sessions ---
|
||||
try:
|
||||
session_count = len(get_conversation_store().list_sessions())
|
||||
except Exception: # noqa: BLE001
|
||||
session_count = 0
|
||||
|
||||
return {
|
||||
"milvus": {"status": milvus_status, **milvus_info},
|
||||
"minio": {"status": minio_status, "connected": minio_connected},
|
||||
"bm25": {"available": bm25 is not None},
|
||||
"reranker": {
|
||||
"enabled": settings.reranker_enabled,
|
||||
"model": settings.reranker_model if settings.reranker_enabled else None,
|
||||
},
|
||||
"sessions": {
|
||||
"active": session_count,
|
||||
"max": settings.session_max_sessions,
|
||||
},
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user