perf/cache-hub-dashboard #2
@@ -6,12 +6,20 @@ from typing import Callable, Optional
|
||||
from fastapi import Request, Response
|
||||
from fastapi.responses import JSONResponse
|
||||
from starlette.middleware.base import BaseHTTPMiddleware
|
||||
from cachetools import TTLCache
|
||||
|
||||
from .config import settings
|
||||
from .security import get_tenant_from_token, verify_token, get_active_system
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# Cache de licencia VÁLIDA por tenant (evita golpear verify-license del Hub en cada
|
||||
# request). Solo el camino "válida" se cachea — inválida/expirada/error nunca se
|
||||
# cachean y siempre revalidan contra el Hub (fail-closed: lo peor que puede pasar es
|
||||
# que un tenant recién revocado siga pasando hasta 5 min más, nunca al revés).
|
||||
_LICENSE_OK_TTL_SECONDS = 300
|
||||
_license_ok_cache: TTLCache = TTLCache(maxsize=1000, ttl=_LICENSE_OK_TTL_SECONDS)
|
||||
|
||||
|
||||
def _normalize_text(value: str | None) -> str:
|
||||
if not value:
|
||||
@@ -160,6 +168,11 @@ class LicenseValidationMiddleware(BaseHTTPMiddleware):
|
||||
if tid is not None and str(tid).strip() != "":
|
||||
tenant_override = str(tid)
|
||||
|
||||
# Licencia ya confirmada válida hace poco para este tenant — no volver a
|
||||
# golpear al Hub (ver definición de _license_ok_cache arriba).
|
||||
if tenant_override and tenant_override in _license_ok_cache:
|
||||
return await call_next(request)
|
||||
|
||||
hub_headers = {"Authorization": f"Bearer {token}"}
|
||||
if tenant_override:
|
||||
hub_headers["X-Tenant-Override"] = str(tenant_override)
|
||||
@@ -274,6 +287,8 @@ class LicenseValidationMiddleware(BaseHTTPMiddleware):
|
||||
pass # Si no se puede parsear, dejamos pasar — el Hub es la fuente de verdad
|
||||
|
||||
request.state.license_info = data
|
||||
if tenant_override:
|
||||
_license_ok_cache[tenant_override] = True
|
||||
return await call_next(request)
|
||||
|
||||
if response.status_code == 401:
|
||||
|
||||
@@ -18,8 +18,10 @@ from .database import get_core_db
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# Cache para tokens verificados (1 minuto de TTL, máximo 1000 tokens)
|
||||
token_cache = TTLCache(maxsize=1000, ttl=60)
|
||||
# Cache para tokens verificados (5 minutos de TTL, máximo 1000 tokens).
|
||||
# El access token vive más que este TTL, así que cachear su verificación es seguro
|
||||
# y evita golpear /auth/me del Hub en cada request de navegación.
|
||||
token_cache = TTLCache(maxsize=1000, ttl=300)
|
||||
|
||||
# IDs de tenants ya sincronizados en este proceso (evita consultas repetidas)
|
||||
_synced_tenant_ids: Set[int] = set()
|
||||
|
||||
Reference in New Issue
Block a user