refactor: uv-based deps, no nexus auth, LLM retries, lock cleanup, health checks, e2e tests

This commit is contained in:
Marker689
2026-05-11 19:27:56 +03:00
parent 698f02c8af
commit 04abe44ab4
20 changed files with 1583 additions and 51 deletions

View File

@@ -1,5 +1,6 @@
"""GuardDog Nexus — FastAPI application entry point."""
import asyncio
import os
import time
from contextlib import asynccontextmanager
@@ -54,10 +55,21 @@ class LangMiddleware(BaseHTTPMiddleware):
async def lifespan(app: FastAPI):
await init_db()
log.info("%s started on %s:%s", APP_NAME, config.host, config.port)
# Start background lock cleanup tasks
asyncio.create_task(_start_lock_cleanup())
yield
log.info("%s shutting down", APP_NAME)
async def _start_lock_cleanup():
"""Start background tasks for cleanup of unused locks."""
from guarddog_nexus.core.harvester import _cleanup_url_locks
from guarddog_nexus.routes.web import _cleanup_llm_locks
asyncio.create_task(_cleanup_url_locks())
asyncio.create_task(_cleanup_llm_locks())
class RequestLoggingMiddleware(BaseHTTPMiddleware):
async def dispatch(self, request: Request, call_next):
start = time.monotonic()
@@ -105,6 +117,43 @@ async def health() -> dict:
return {"status": "ok", "version": APP_VERSION}
@app.get("/health/dependencies")
async def health_dependencies() -> JSONResponse:
"""Check health of external dependencies."""
checks = {
"database": await _check_db_health(),
"nexus": await _check_nexus_connectivity(),
}
status = 200 if all(checks.values()) else 503
return JSONResponse(status_code=status, content=checks)
async def _check_db_health() -> bool:
"""Check if database is accessible."""
from sqlalchemy import text
try:
from guarddog_nexus.db.engine import _engine
async with _engine.connect() as conn:
await conn.execute(text("SELECT 1"))
return True
except Exception:
return False
async def _check_nexus_connectivity() -> bool:
"""Check if Nexus API is reachable."""
import httpx
try:
async with httpx.AsyncClient(timeout=10) as client:
resp = await client.get(f"{config.nexus_url.rstrip('/')}/service/rest/v1/status")
return resp.status_code == 200
except Exception:
return False
def main():
uvicorn.run(
f"{APP_PACKAGE}.main:app",