Actualizar docker-compose.yml con sintaxis YAML corregida y puerto 80 para frontend
This commit is contained in:
@@ -1,5 +1,8 @@
|
||||
# backend/cache_manager.py
|
||||
"""Caché global en memoria con refresco en segundo plano (igual que el dashboard de ventas)."""
|
||||
"""
|
||||
Caché global en memoria con refresco en segundo plano.
|
||||
Independiente de Streamlit. Mantiene los datos calientes para respuestas instantáneas.
|
||||
"""
|
||||
import time
|
||||
import threading
|
||||
from typing import Any, Callable, Dict, Tuple
|
||||
@@ -13,25 +16,37 @@ def _make_key(prefix: str, args: tuple) -> str:
|
||||
return prefix + ":" + "|".join(str(a) for a in args)
|
||||
|
||||
|
||||
def cache_get_or_set(prefix: str, args: tuple, loader: Callable[[], Any], ttl: int = _DEFAULT_TTL) -> Any:
|
||||
def cache_get_or_set(prefix: str, args: tuple, loader: Callable[[], Any],
|
||||
ttl: int = _DEFAULT_TTL) -> Any:
|
||||
"""Devuelve el valor cacheado si está fresco; si no, lo calcula y guarda."""
|
||||
key = _make_key(prefix, args)
|
||||
now = time.time()
|
||||
with _LOCK:
|
||||
hit = _CACHE.get(key)
|
||||
if hit and (now - hit[0] < ttl):
|
||||
return hit[1]
|
||||
# Calcular fuera del lock (puede tardar)
|
||||
value = loader()
|
||||
with _LOCK:
|
||||
_CACHE[key] = (now, value)
|
||||
return value
|
||||
|
||||
|
||||
def cache_set(prefix: str, args: tuple, value: Any) -> None:
|
||||
key = _make_key(prefix, args)
|
||||
with _LOCK:
|
||||
_CACHE[key] = (time.time(), value)
|
||||
|
||||
|
||||
def cache_keys():
|
||||
"""Lista las claves actualmente cacheadas (para refrescarlas sin vaciar)."""
|
||||
with _LOCK:
|
||||
return list(_CACHE.keys())
|
||||
|
||||
|
||||
def cache_refresh_existing(loader_for_key):
|
||||
"""Recalcula SOLO las entradas que ya existen, sin vaciar el caché.
|
||||
Así los meses ya visitados se mantienen calientes y nunca quedan 'fríos'."""
|
||||
for key in cache_keys():
|
||||
try:
|
||||
nuevo = loader_for_key(key)
|
||||
@@ -43,6 +58,7 @@ def cache_refresh_existing(loader_for_key):
|
||||
|
||||
|
||||
def cache_invalidate(prefix: str = None) -> None:
|
||||
"""Invalida todo el caché, o solo las claves de un prefijo."""
|
||||
with _LOCK:
|
||||
if prefix is None:
|
||||
_CACHE.clear()
|
||||
@@ -57,10 +73,13 @@ def cache_stats() -> dict:
|
||||
return {"entradas": len(_CACHE), "claves": list(_CACHE.keys())}
|
||||
|
||||
|
||||
# ── Refresco en segundo plano ──────────────────────────────────────────────
|
||||
_background_started = False
|
||||
|
||||
|
||||
def start_background_refresh(refresh_fn: Callable[[], None], interval: int = 900):
|
||||
def start_background_refresh(refresh_fn: Callable[[], None], interval: int = 240):
|
||||
"""Lanza un hilo que ejecuta refresh_fn cada `interval` segundos (4 min por defecto,
|
||||
antes de que expire el TTL de 5 min, para mantener el caché siempre caliente)."""
|
||||
global _background_started
|
||||
if _background_started:
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user