""" backend/api/benchmarks_hub.py — Gap 3: router per i 3 benchmark standalone Espone come endpoint HTTP le classi benchmark finora orfane: POST /api/debug/benchmark/advanced ← AdvancedBenchmark (concorrenza) POST /api/debug/benchmark/fabric ← FabricBenchmark (token rotation) POST /api/debug/benchmark/extended ← ExtendedBenchmark (multi-scenario) Tutti usano mock interni (asyncio.sleep + dict simulati) — sicuri da eseguire in produzione senza side-effect su provider reali. """ import asyncio, logging, time from fastapi import APIRouter from fastapi.responses import JSONResponse router = APIRouter() _logger = logging.getLogger("api.benchmarks_hub") @router.post("/api/debug/benchmark/advanced") async def run_advanced() -> JSONResponse: """Stress test concorrenza: 3 scenari × N task simulati.""" t0 = time.monotonic() try: from api.advanced_complex_benchmark import AdvancedBenchmark b = AdvancedBenchmark() await b.setup() await asyncio.gather( b.run_complex_task("complex_reasoning", "reasoning", count=5), b.run_complex_task("data_heavy_sync", "memory", count=5), b.run_complex_task("multi_provider_chain","compute", count=5), ) elapsed = round((time.monotonic() - t0) * 1000) total = b.metrics["successes"] + b.metrics["failures"] return JSONResponse({ "ok": True, "type": "advanced", "elapsed_ms": elapsed, "success_rate": round(b.metrics["successes"] / max(1, total) * 100, 1), "total_calls": total, "successes": b.metrics["successes"], "failures": b.metrics["failures"], "latencies": { k: {"avg_ms": round(sum(v) / len(v), 1), "max_ms": round(max(v), 1), "n": len(v)} for k, v in b.metrics.items() if isinstance(v, list) and v }, }) except Exception as exc: _logger.exception("[advanced_bench]") return JSONResponse({"ok": False, "type": "advanced", "error": str(exc)}, status_code=500) @router.post("/api/debug/benchmark/fabric") async def run_fabric() -> JSONResponse: """Benchmark rotazione token e fallback provider.""" t0 = time.monotonic() try: from api.fabric_benchmark import FabricBenchmark b = FabricBenchmark() await b.setup_simulated_environment() await b.run_benchmark() elapsed = round((time.monotonic() - t0) * 1000) lats = b.stats.get("latencies", []) return JSONResponse({ "ok": True, "type": "fabric", "elapsed_ms": elapsed, "rotations": b.stats.get("rotations", 0), "fallbacks": b.stats.get("fallbacks", 0), "errors": len(b.stats.get("errors", [])), "avg_latency_ms": round(sum(lats) / len(lats), 1) if lats else None, }) except Exception as exc: _logger.exception("[fabric_bench]") return JSONResponse({"ok": False, "type": "fabric", "error": str(exc)}, status_code=500) @router.post("/api/debug/benchmark/extended") async def run_extended() -> JSONResponse: """Multi-scenario: normal load + cascading failure + oracle stress.""" t0 = time.monotonic() try: from api.extended_benchmark import ExtendedBenchmark b = ExtendedBenchmark() await b.setup() await asyncio.gather( b.scenario_normal_load(), b.scenario_cascading_failure(), b.scenario_oracle_stress(), ) elapsed = round((time.monotonic() - t0) * 1000) return JSONResponse({ "ok": True, "type": "extended", "elapsed_ms": elapsed, "scenarios": b.results, }) except Exception as exc: _logger.exception("[extended_bench]") return JSONResponse({"ok": False, "type": "extended", "error": str(exc)}, status_code=500)