126 lines
3.4 KiB
Python
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
|