admin / Syanpse-Vanguard
public
Syanpse-Vanguard / synapse-vanguard-v3 / sv / main.py
2185 B · main
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | """Consolidated single-process entrypoint (homelab / embedded-DuckDB default). DuckDB is embedded and single-writer: only ONE OS process may hold the database file. Running the API, agent-ingest, and normalizer as separate containers all pointing at the same file causes a lock-conflict crash loop. So the default deployment runs them together in one process on one shared engine + broker: uvicorn sv.main:app --host 0.0.0.0 --port 5500 • API + web UI + agent-ingest routes -> mounted routers (shared app.state) • normalizer -> asyncio background task on the same engine/broker For enterprise scale, switch SV_STORAGE_BACKEND=clickhouse (external shared DB) and the microservice compose profile can fan these back out into separate containers. """ from __future__ import annotations import asyncio import logging from contextlib import asynccontextmanager from fastapi import FastAPI from sv.api import router as api_router from sv.bootstrap import shutdown, startup from sv.config import settings from sv.ingest.agent_api import router as ingest_router from sv.metrics import EpsMeter from sv.pipeline.normalizer import default_consumer, run_loop log = logging.getLogger("sv.main") @asynccontextmanager async def lifespan(app: FastAPI): engine, broker = await startup(with_broker=True) app.state.engine, app.state.broker = engine, broker app.state.eps_meter = EpsMeter() stop = asyncio.Event() normalizer = asyncio.create_task( run_loop(engine, broker, stop, default_consumer()), name="normalizer", ) log.info("consolidated app ready (api + ingest + normalizer)") try: yield finally: stop.set() normalizer.cancel() try: await normalizer except asyncio.CancelledError: pass await shutdown(engine, broker) app = FastAPI(title="Synapse-Vanguard", lifespan=lifespan) # api_router owns "/" (dashboard) + /v1/auth, /v1/search, /v1/agents, /v1/me. # ingest_router owns /v1/agents/register + /v1/ingest/bulk. app.include_router(api_router) app.include_router(ingest_router) |