Files
OLD-server-architecture/copernicus/core/cache.py

126 lines
3.4 KiB
Python

"""
Redis Keys:
- marine:catalog:full → lista dei dataset completo (TTL 1h)
- marine:catalog:search:{hash} → risultati ricerca (TTL 30min)
- marine:job:{session_id} → stato job download (TTL 48h)
"""
import json
import os
import logging
from typing import Any, Optional
import redis
logger = logging.getLogger(__name__)
# Configurazione Redis da variabili ambiente
REDIS_HOST = os.getenv("REDIS_HOST", "meb-redis")
REDIS_PORT = int(os.getenv("REDIS_PORT", "6379"))
# Pool di connessioni condiviso (thread-safe, riutilizzabile)
_pool: Optional[redis.ConnectionPool] = None
_client: Optional[redis.Redis] = None
def _get_client() -> Optional[redis.Redis]:
"""Restituisce il client Redis singleton con connection pool.
Ritorna None se Redis non è raggiungibile."""
global _pool, _client
if _client is not None:
return _client
try:
_pool = redis.ConnectionPool(
host=REDIS_HOST,
port=REDIS_PORT,
# Decodifica automatica delle risposte in stringhe UTF-8
decode_responses=True,
# Massimo 5 connessioni nel pool (VPS 1-core, non serve di più)
max_connections=5,
# Timeout connessione e socket per evitare blocchi
socket_connect_timeout=3,
socket_timeout=3,
# Riprova automaticamente se la connessione viene interrotta
retry_on_timeout=True,
)
_client = redis.Redis(connection_pool=_pool)
# Test connessione
_client.ping()
logger.info("[Redis] Connessione stabilita per il servizio Marine")
return _client
except Exception as e:
logger.warning(f"[Redis] Non disponibile, la cache è disabilitata: {e}")
_client = None
return None
def cache_get(key: str) -> Optional[Any]:
"""Legge un valore dalla cache Redis.
Args:
key: Chiave Redis (es. 'marine:catalog:full')
Returns:
Il valore deserializzato da JSON, oppure None se non trovato o errore
"""
try:
client = _get_client()
if client is None:
return None
data = client.get(key)
if data is None:
return None
return json.loads(data)
except Exception as e:
logger.warning(f"[Redis] Errore lettura chiave '{key}': {e}")
return None
def cache_set(key: str, value: Any, ttl: int = 3600) -> bool:
"""Scrive un valore nella cache Redis con TTL.
Args:
key: Chiave Redis
value: Valore da serializzare in JSON
ttl: Tempo di vita in secondi (default: 1 ora)
Returns:
True se scritto con successo, False altrimenti
"""
try:
client = _get_client()
if client is None:
return False
serialized = json.dumps(value)
client.setex(key, ttl, serialized)
return True
except Exception as e:
logger.warning(f"[Redis] Errore scrittura chiave '{key}': {e}")
return False
def cache_delete(key: str) -> bool:
"""Elimina una chiave dalla cache Redis.
Args:
key: Chiave Redis da eliminare
Returns:
True se eliminata, False altrimenti
"""
try:
client = _get_client()
if client is None:
return False
client.delete(key)
return True
except Exception as e:
logger.warning(f"[Redis] Errore eliminazione chiave '{key}': {e}")
return False