Catalyst / admin/Syanpse-Vanguard 14.8 GB / 57.8 GB 40.0 GB free
Help Sign in

admin / Syanpse-Vanguard

public
Code Issues Pull requests Pipelines Packages Security Insights Wiki Settings
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)