perf/cache-hub-dashboard #2

Merged
Kevin_Ramirez merged 4 commits from perf/cache-hub-dashboard into main 2026-07-21 21:33:43 +00:00
2 changed files with 19 additions and 2 deletions
Showing only changes of commit a1bbb6b1b2 - Show all commits

View File

@@ -6,12 +6,20 @@ from typing import Callable, Optional
from fastapi import Request, Response from fastapi import Request, Response
from fastapi.responses import JSONResponse from fastapi.responses import JSONResponse
from starlette.middleware.base import BaseHTTPMiddleware from starlette.middleware.base import BaseHTTPMiddleware
from cachetools import TTLCache
from .config import settings from .config import settings
from .security import get_tenant_from_token, verify_token, get_active_system from .security import get_tenant_from_token, verify_token, get_active_system
logger = logging.getLogger(__name__) 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: def _normalize_text(value: str | None) -> str:
if not value: if not value:
@@ -160,6 +168,11 @@ class LicenseValidationMiddleware(BaseHTTPMiddleware):
if tid is not None and str(tid).strip() != "": if tid is not None and str(tid).strip() != "":
tenant_override = str(tid) 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}"} hub_headers = {"Authorization": f"Bearer {token}"}
if tenant_override: if tenant_override:
hub_headers["X-Tenant-Override"] = str(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 pass # Si no se puede parsear, dejamos pasar — el Hub es la fuente de verdad
request.state.license_info = data request.state.license_info = data
if tenant_override:
_license_ok_cache[tenant_override] = True
return await call_next(request) return await call_next(request)
if response.status_code == 401: if response.status_code == 401:

View File

@@ -18,8 +18,10 @@ from .database import get_core_db
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
# Cache para tokens verificados (1 minuto de TTL, máximo 1000 tokens) # Cache para tokens verificados (5 minutos de TTL, máximo 1000 tokens).
token_cache = TTLCache(maxsize=1000, ttl=60) # 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) # IDs de tenants ya sincronizados en este proceso (evita consultas repetidas)
_synced_tenant_ids: Set[int] = set() _synced_tenant_ids: Set[int] = set()