mirror of
https://github.com/azaion/gps-denied-onboard.git
synced 2026-06-21 08:41:12 +00:00
feat(01-08): rewire app.py lifespan and deps.py to use build_pipeline
- app.py: replace inline component wiring with build_pipeline(env=cfg.env) - Store processor as app.state.processor (and backwards-compat pipeline_components) - RuntimeConfig replaces get_settings(); MAVLink stop() on shutdown - deps.py: get_flight_processor prefers app.state.processor from lifespan - Falls back to build_pipeline() for test contexts without lifespan - Per-request repo/streamer swap preserved
This commit is contained in:
@@ -5,7 +5,7 @@ from fastapi import Depends, HTTPException, Request
|
||||
from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from gps_denied.config import get_settings
|
||||
from gps_denied.config import RuntimeConfig, get_settings
|
||||
from gps_denied.core.processor import FlightProcessor
|
||||
from gps_denied.core.sse import SSEEventStreamer
|
||||
from gps_denied.db.engine import get_session
|
||||
@@ -65,14 +65,23 @@ async def get_flight_processor(
|
||||
) -> FlightProcessor:
|
||||
global _processor
|
||||
if _processor is None:
|
||||
eskf_config = getattr(request.app.state, "eskf_config", None)
|
||||
_processor = FlightProcessor(repo, sse, eskf_config=eskf_config)
|
||||
# Підключаємо pipeline компоненти з lifespan
|
||||
components = getattr(request.app.state, "pipeline_components", None)
|
||||
if components:
|
||||
_processor.attach_components(**components)
|
||||
# Оновлюємо repo (нова сесія на кожен запит)
|
||||
# Prefer the processor already built by lifespan (via build_pipeline)
|
||||
lifespan_processor = getattr(request.app.state, "processor", None)
|
||||
if lifespan_processor is not None:
|
||||
_processor = lifespan_processor
|
||||
else:
|
||||
# Fallback: build pipeline directly (e.g. in tests without lifespan)
|
||||
from gps_denied.pipeline import build_pipeline
|
||||
_settings = RuntimeConfig()
|
||||
_processor = build_pipeline(
|
||||
env=_settings.env,
|
||||
config=_settings,
|
||||
repository=repo,
|
||||
streamer=sse,
|
||||
)
|
||||
# Оновлюємо repo та streamer (нова сесія на кожен запит)
|
||||
_processor.repository = repo
|
||||
_processor.streamer = sse
|
||||
return _processor
|
||||
|
||||
|
||||
|
||||
+28
-48
@@ -7,70 +7,50 @@ from fastapi import FastAPI
|
||||
|
||||
from gps_denied import __version__
|
||||
from gps_denied.api.routers import flights
|
||||
from gps_denied.config import get_settings
|
||||
from gps_denied.config import RuntimeConfig
|
||||
from gps_denied.pipeline import build_pipeline
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@asynccontextmanager
|
||||
async def lifespan(app: FastAPI):
|
||||
"""Initialise core pipeline components on startup."""
|
||||
from gps_denied.core.chunk_manager import RouteChunkManager
|
||||
from gps_denied.core.coordinates import CoordinateTransformer
|
||||
from gps_denied.core.gpr import GlobalPlaceRecognition
|
||||
from gps_denied.core.graph import FactorGraphOptimizer
|
||||
from gps_denied.core.mavlink import MAVLinkBridge
|
||||
from gps_denied.core.metric import MetricRefinement
|
||||
from gps_denied.core.models import ModelManager
|
||||
from gps_denied.core.recovery import FailureRecoveryCoordinator
|
||||
from gps_denied.core.rotation import ImageRotationManager
|
||||
from gps_denied.core.satellite import SatelliteDataManager
|
||||
from gps_denied.core.vo import create_vo_backend
|
||||
from gps_denied.schemas.eskf import ESKFConfig
|
||||
from gps_denied.schemas.graph import FactorGraphConfig
|
||||
"""Initialise core pipeline components on startup via build_pipeline."""
|
||||
cfg = RuntimeConfig()
|
||||
processor = build_pipeline(env=cfg.env, config=cfg)
|
||||
|
||||
settings = get_settings()
|
||||
# Retrieve MAVLink bridge from processor internals for lifecycle management
|
||||
mavlink = processor._mavlink
|
||||
|
||||
mm = ModelManager(engine_dir=str(settings.models.weights_dir))
|
||||
vo = create_vo_backend(model_manager=mm)
|
||||
gpr = GlobalPlaceRecognition(mm)
|
||||
metric = MetricRefinement(mm)
|
||||
graph = FactorGraphOptimizer(FactorGraphConfig())
|
||||
chunk_mgr = RouteChunkManager(graph)
|
||||
recovery = FailureRecoveryCoordinator(chunk_mgr, gpr, metric)
|
||||
rotation = ImageRotationManager(mm)
|
||||
coord = CoordinateTransformer()
|
||||
satellite = SatelliteDataManager(tile_dir=settings.satellite.tile_dir)
|
||||
mavlink = MAVLinkBridge(
|
||||
connection_string=settings.mavlink.connection,
|
||||
output_hz=settings.mavlink.output_hz,
|
||||
telemetry_hz=settings.mavlink.telemetry_hz,
|
||||
)
|
||||
|
||||
# ESKF config from env vars (per-airframe tuning)
|
||||
eskf_config = ESKFConfig(**settings.eskf.model_dump())
|
||||
|
||||
# Store on app.state so deps can access them
|
||||
app.state.processor = processor
|
||||
app.state.config = cfg
|
||||
# Keep backwards-compat key so any code reading pipeline_components still works
|
||||
app.state.pipeline_components = {
|
||||
"vo": vo, "gpr": gpr, "metric": metric,
|
||||
"graph": graph, "recovery": recovery,
|
||||
"chunk_mgr": chunk_mgr, "rotation": rotation,
|
||||
"coord": coord, "satellite": satellite,
|
||||
"vo": processor._vo,
|
||||
"gpr": processor._gpr,
|
||||
"metric": processor._metric,
|
||||
"graph": processor._graph,
|
||||
"recovery": processor._recovery,
|
||||
"chunk_mgr": processor._chunk_mgr,
|
||||
"rotation": processor._rotation,
|
||||
"coord": processor._coord,
|
||||
"satellite": processor._satellite,
|
||||
"mavlink": mavlink,
|
||||
}
|
||||
app.state.eskf_config = eskf_config
|
||||
app.state.eskf_config = processor._eskf_config
|
||||
|
||||
logger.info(
|
||||
"Pipeline ready — MAVLink: %s, tiles: %s",
|
||||
settings.mavlink.connection, settings.satellite.tile_dir,
|
||||
"Pipeline ready — env=%s, MAVLink: %s, tiles: %s",
|
||||
cfg.env, cfg.mavlink.connection, cfg.satellite.tile_dir,
|
||||
)
|
||||
yield
|
||||
|
||||
# Cleanup
|
||||
try:
|
||||
await mavlink.stop()
|
||||
except Exception:
|
||||
pass
|
||||
# Cleanup MAVLink on shutdown
|
||||
if mavlink is not None:
|
||||
try:
|
||||
await mavlink.stop()
|
||||
except Exception:
|
||||
pass
|
||||
app.state.pipeline_components = None
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user