fix(viewer+backend): cache sorties TTL 10min + /sorties/local + viewer non-bloquant
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import asyncio
|
||||
import gzip
|
||||
import json
|
||||
import time
|
||||
from pathlib import Path
|
||||
from typing import AsyncGenerator
|
||||
|
||||
@@ -9,7 +10,7 @@ from fastapi.middleware.cors import CORSMiddleware
|
||||
from fastapi.responses import JSONResponse, StreamingResponse
|
||||
|
||||
from .config import OUTPUT_DIR
|
||||
from .runner import run_pipeline, scan_sorties
|
||||
from .runner import run_pipeline, scan_sorties, scan_sorties_local
|
||||
|
||||
app = FastAPI(title="COSMA Pipeline Runner")
|
||||
app.add_middleware(CORSMiddleware, allow_origins=["*"], allow_methods=["*"], allow_headers=["*"])
|
||||
@@ -17,10 +18,51 @@ app.add_middleware(CORSMiddleware, allow_origins=["*"], allow_methods=["*"], all
|
||||
# Active pipeline jobs: sortie_id → asyncio.Queue
|
||||
_jobs: dict[str, asyncio.Queue] = {}
|
||||
|
||||
# Cache sorties avec TTL 10min
|
||||
_sorties_cache: list | None = None
|
||||
_sorties_cache_ts: float = 0.0
|
||||
_SORTIES_TTL = 600.0 # 10 minutes
|
||||
_sorties_refresh_lock: asyncio.Lock | None = None
|
||||
|
||||
|
||||
def _get_lock() -> asyncio.Lock:
|
||||
global _sorties_refresh_lock
|
||||
if _sorties_refresh_lock is None:
|
||||
_sorties_refresh_lock = asyncio.Lock()
|
||||
return _sorties_refresh_lock
|
||||
|
||||
|
||||
async def _refresh_sorties_cache() -> None:
|
||||
"""Refresh cache in background (holds lock to avoid parallel rclone calls)."""
|
||||
global _sorties_cache, _sorties_cache_ts
|
||||
lock = _get_lock()
|
||||
async with lock:
|
||||
# Double-check after acquiring lock
|
||||
if time.monotonic() - _sorties_cache_ts < _SORTIES_TTL:
|
||||
return
|
||||
result = await asyncio.to_thread(scan_sorties)
|
||||
_sorties_cache = result
|
||||
_sorties_cache_ts = time.monotonic()
|
||||
|
||||
|
||||
@app.get("/sorties")
|
||||
async def list_sorties():
|
||||
return await scan_sorties()
|
||||
global _sorties_cache, _sorties_cache_ts
|
||||
now = time.monotonic()
|
||||
if _sorties_cache is None:
|
||||
# Premier appel: bloquant (cache vide)
|
||||
await _refresh_sorties_cache()
|
||||
elif now - _sorties_cache_ts >= _SORTIES_TTL:
|
||||
# Cache périmé: retourne le cache, refresh en arrière-plan
|
||||
asyncio.create_task(_refresh_sorties_cache())
|
||||
return _sorties_cache or []
|
||||
|
||||
|
||||
@app.get("/sorties/local")
|
||||
async def list_sorties_local():
|
||||
"""Scan /data/sorties local (NAS, instantané) sans rclone."""
|
||||
sorties = await asyncio.to_thread(scan_sorties_local)
|
||||
return sorties
|
||||
|
||||
|
||||
@app.post("/run/{sortie_id:path}")
|
||||
|
||||
Reference in New Issue
Block a user