Lifespan

from contextlib import asynccontextmanager

@asynccontextmanager
async def lifespan(app):
    # STARTUP — runs before first request
    await map_client.connect()
    
    yield   # ← app runs here, handling requests
    
    # SHUTDOWN — runs after last request
    await map_client.close()

app = FastAPI(lifespan=lifespan)

main.py

from fastapi import FastAPI, APIRouter, HTTPException

app = FastAPI()
router = APIRouter(prefix="/drones", tags=["drones"])

/routers/drones

@router.get("/{drone_id}/battery", response_model=BatteryResult)
async def battery(drone_id: str, body: BatteryRequest) -> BatteryResult:
    drone = _lookup(drone_id)
    return await get_battery_status(drone)

Singleton

# registry.py
_state: dict[str, Drone | None] = {"drone": None}

def set_drone(drone: Drone) -> None:
    _state["drone"] = drone

def get_drone() -> Drone | None:
    return _state["drone"]