Terminal / api /global_state_sync_with_oracle.py
Baida—-
fix(registry): unterminated string literal line 692 — force re-sync [skip ci]
889ea3f verified
Raw
History Blame Contribute Delete
14.7 kB
"""
global_state_sync_with_oracle.py — Sincronizzazione Globale con Nodo E (Oracle)
Integra il Nodo E (Oracle Cloud) nella logica di sincronizzazione del cluster.
Architettura:
B (PRIMARY): Stato globale, transazioni critiche
C (Memory/RAG): Embeddings, conversazioni
D (Audit): Event log, compliance
E (Compute): Task distribuiti, carichi pesanti
A (Cache): Read-only, analytics
Flussi di Sincronizzazione:
- B ↔ C: Memoria bidirezionale
- B → D: Audit unidirezionale
- B → E: Task distribuiti
- E → B: Risultati task
- A: Nessuna (read-only)
"""
import os
import asyncio
import logging
from typing import Dict, List, Any, Optional
from datetime import datetime, timedelta
from enum import Enum
import json
_logger = logging.getLogger("global_state_sync_oracle")
# ── Configurazione Nodi ────────────────────────────────────────────────────
ORACLE_NODE_E_ENABLED = os.getenv("ORACLE_NODE_E_ENABLED", "true").lower() == "true"
ORACLE_NODE_E_IP = os.getenv("ORACLE_NODE_E_IP", "80.225.89.217")
ORACLE_NODE_E_PORT = int(os.getenv("ORACLE_NODE_E_PORT", "8080"))
SYNC_INTERVAL_SECONDS = int(os.getenv("SYNC_INTERVAL_SECONDS", "30"))
SYNC_BATCH_SIZE = int(os.getenv("SYNC_BATCH_SIZE", "100"))
SYNC_TIMEOUT_SECONDS = int(os.getenv("SYNC_TIMEOUT_SECONDS", "60"))
# ── Enumerazione Tipo Sincronizzazione ─────────────────────────────────────
class SyncType(str, Enum):
MEMORY = "memory" # B ↔ C
AUDIT = "audit" # B → D
TASK = "task" # B → E
RESULT = "result" # E → B
CACHE = "cache" # A (read-only)
# ── Classe Sincronizzatore ────────────────────────────────────────────────
class GlobalStateSyncWithOracle:
"""Gestore sincronizzazione globale con Nodo E."""
def __init__(self):
self.sync_history = []
self.pending_tasks = []
self.last_sync_time = {}
self.sync_stats = {
"total_syncs": 0,
"successful_syncs": 0,
"failed_syncs": 0,
"total_items_synced": 0,
}
async def sync_memory(self, session_id: str) -> Dict[str, Any]:
"""Sincronizza memoria tra B e C."""
try:
_logger.info(f"Sincronizzazione memoria: {session_id}")
# Recupera memoria da B
memory_b = await self._fetch_from_node_b(f"agent_memory:{session_id}")
# Sincronizza su C
await self._sync_to_node_c(f"agent_memory:{session_id}", memory_b)
# Sincronizza su E (se abilitato e ha task correlati)
if ORACLE_NODE_E_ENABLED:
await self._sync_to_node_e(f"memory:{session_id}", memory_b)
self.sync_stats["successful_syncs"] += 1
self.sync_stats["total_items_synced"] += 1
return {
"ok": True,
"session_id": session_id,
"synced_to": ["B", "C", "E"] if ORACLE_NODE_E_ENABLED else ["B", "C"],
}
except Exception as exc:
_logger.error(f"Errore sincronizzazione memoria: {exc}")
self.sync_stats["failed_syncs"] += 1
return {"ok": False, "error": str(exc)}
async def sync_audit(self, event: Dict[str, Any]) -> Dict[str, Any]:
"""Sincronizza evento audit da B a D."""
try:
_logger.info(f"Sincronizzazione audit: {event.get('event_type')}")
# Sincronizza su D (append-only)
await self._sync_to_node_d("audit_event", event)
# Log anche su E se è un evento critico
if ORACLE_NODE_E_ENABLED and event.get("severity") in ["critical", "error"]:
await self._sync_to_node_e("audit_log", event)
self.sync_stats["successful_syncs"] += 1
self.sync_stats["total_items_synced"] += 1
return {
"ok": True,
"event_id": event.get("id"),
"synced_to": ["D", "E"] if ORACLE_NODE_E_ENABLED else ["D"],
}
except Exception as exc:
_logger.error(f"Errore sincronizzazione audit: {exc}")
self.sync_stats["failed_syncs"] += 1
return {"ok": False, "error": str(exc)}
async def distribute_task_to_oracle(self, task: Dict[str, Any]) -> Dict[str, Any]:
"""Distribuisce un task computazionale al Nodo E (Oracle)."""
if not ORACLE_NODE_E_ENABLED:
return {"ok": False, "error": "Oracle Node E disabilitato"}
try:
_logger.info(f"Distribuzione task a Nodo E: {task.get('id')}")
# Salva task in B (PRIMARY)
task_id = await self._save_task_to_node_b(task)
# Invia task a E
result = await self._send_task_to_node_e(task_id, task)
if result.get("ok"):
self.pending_tasks.append({
"task_id": task_id,
"node": "E",
"created_at": datetime.now().isoformat(),
"status": "pending",
})
self.sync_stats["successful_syncs"] += 1
else:
self.sync_stats["failed_syncs"] += 1
return result
except Exception as exc:
_logger.error(f"Errore distribuzione task: {exc}")
self.sync_stats["failed_syncs"] += 1
return {"ok": False, "error": str(exc)}
async def collect_task_results(self) -> Dict[str, Any]:
"""Raccoglie i risultati dei task dal Nodo E."""
if not ORACLE_NODE_E_ENABLED:
return {"ok": False, "error": "Oracle Node E disabilitato"}
try:
_logger.info("Raccolta risultati task da Nodo E...")
results = []
for task_info in self.pending_tasks[:]:
if task_info["node"] == "E":
result = await self._fetch_task_result_from_node_e(task_info["task_id"])
if result.get("ok") and result.get("status") == "completed":
# Sincronizza risultato su B
await self._sync_result_to_node_b(task_info["task_id"], result)
results.append(result)
self.pending_tasks.remove(task_info)
self.sync_stats["successful_syncs"] += 1
return {
"ok": True,
"results_collected": len(results),
"pending_tasks": len(self.pending_tasks),
"results": results,
}
except Exception as exc:
_logger.error(f"Errore raccolta risultati: {exc}")
return {"ok": False, "error": str(exc)}
async def sync_all(self) -> Dict[str, Any]:
"""Sincronizzazione completa tra tutti i nodi."""
try:
_logger.info("Sincronizzazione completa iniziata...")
start_time = datetime.now()
# 1. Sincronizza memoria (B ↔ C)
memory_sync = await self._sync_all_memory()
# 2. Sincronizza audit (B → D)
audit_sync = await self._sync_all_audit()
# 3. Raccoglie risultati task da E
task_results = None
if ORACLE_NODE_E_ENABLED:
task_results = await self.collect_task_results()
elapsed = (datetime.now() - start_time).total_seconds()
self.sync_stats["total_syncs"] += 1
self.last_sync_time["all"] = datetime.now().isoformat()
return {
"ok": True,
"memory_synced": memory_sync.get("count", 0),
"audit_synced": audit_sync.get("count", 0),
"task_results_collected": task_results.get("results_collected", 0) if task_results else 0,
"elapsed_seconds": elapsed,
"stats": self.sync_stats,
}
except Exception as exc:
_logger.error(f"Errore sincronizzazione completa: {exc}")
self.sync_stats["failed_syncs"] += 1
return {"ok": False, "error": str(exc)}
# ── Metodi Privati ────────────────────────────────────────────────────
async def _fetch_from_node_b(self, key: str) -> Any:
"""Recupera dato da Nodo B (PRIMARY)."""
# Implementazione: Query Supabase B
_logger.debug(f"Fetch da B: {key}")
return {} # Placeholder
async def _sync_to_node_c(self, key: str, data: Any) -> bool:
"""Sincronizza dato a Nodo C (Memory/RAG)."""
# Implementazione: Insert/Update Supabase C
_logger.debug(f"Sync a C: {key}")
return True # Placeholder
async def _sync_to_node_d(self, key: str, data: Any) -> bool:
"""Sincronizza evento audit a Nodo D (Audit)."""
# Implementazione: Append-only insert Supabase D
_logger.debug(f"Sync a D: {key}")
return True # Placeholder
async def _sync_to_node_e(self, key: str, data: Any) -> bool:
"""Sincronizza dato a Nodo E (Oracle Compute)."""
if not ORACLE_NODE_E_ENABLED:
return False
try:
import httpx
async with httpx.AsyncClient() as client:
response = await client.post(
f"http://{ORACLE_NODE_E_IP}:{ORACLE_NODE_E_PORT}/api/sync/receive",
json={"key": key, "data": data},
timeout=SYNC_TIMEOUT_SECONDS,
)
return response.status_code == 200
except Exception as exc:
_logger.error(f"Errore sync a E: {exc}")
return False
async def _save_task_to_node_b(self, task: Dict[str, Any]) -> str:
"""Salva task in B."""
# Implementazione: Insert Supabase B
_logger.debug(f"Save task a B: {task.get('id')}")
return task.get("id", "task_unknown") # Placeholder
async def _send_task_to_node_e(self, task_id: str, task: Dict[str, Any]) -> Dict[str, Any]:
"""Invia task a Nodo E."""
if not ORACLE_NODE_E_ENABLED:
return {"ok": False, "error": "Oracle Node E disabilitato"}
try:
import httpx
async with httpx.AsyncClient() as client:
response = await client.post(
f"http://{ORACLE_NODE_E_IP}:{ORACLE_NODE_E_PORT}/api/tasks/submit",
json={"task_id": task_id, "task": task},
timeout=SYNC_TIMEOUT_SECONDS,
)
return response.json() if response.status_code == 200 else {"ok": False}
except Exception as exc:
_logger.error(f"Errore invio task a E: {exc}")
return {"ok": False, "error": str(exc)}
async def _fetch_task_result_from_node_e(self, task_id: str) -> Dict[str, Any]:
"""Recupera risultato task da Nodo E."""
if not ORACLE_NODE_E_ENABLED:
return {"ok": False}
try:
import httpx
async with httpx.AsyncClient() as client:
response = await client.get(
f"http://{ORACLE_NODE_E_IP}:{ORACLE_NODE_E_PORT}/api/tasks/{task_id}/result",
timeout=SYNC_TIMEOUT_SECONDS,
)
return response.json() if response.status_code == 200 else {"ok": False}
except Exception as exc:
_logger.error(f"Errore fetch risultato da E: {exc}")
return {"ok": False}
async def _sync_result_to_node_b(self, task_id: str, result: Dict[str, Any]) -> bool:
"""Sincronizza risultato task a B."""
# Implementazione: Update Supabase B
_logger.debug(f"Sync risultato a B: {task_id}")
return True # Placeholder
async def _sync_all_memory(self) -> Dict[str, Any]:
"""Sincronizza tutta la memoria."""
_logger.debug("Sincronizzazione memoria completa...")
return {"count": 0} # Placeholder
async def _sync_all_audit(self) -> Dict[str, Any]:
"""Sincronizza tutti gli audit."""
_logger.debug("Sincronizzazione audit completa...")
return {"count": 0} # Placeholder
# ── Istanza Globale ───────────────────────────────────────────────────────
_sync_manager = GlobalStateSyncWithOracle()
# ── Scheduler Sincronizzazione ────────────────────────────────────────────
async def start_sync_scheduler():
"""Avvia lo scheduler di sincronizzazione periodica."""
_logger.info(f"Avvio scheduler sincronizzazione (intervallo: {SYNC_INTERVAL_SECONDS}s)...")
while True:
try:
await asyncio.sleep(SYNC_INTERVAL_SECONDS)
result = await _sync_manager.sync_all()
if result.get("ok"):
_logger.info(f"Sincronizzazione completata: {result}")
else:
_logger.warning(f"Sincronizzazione parziale: {result}")
except Exception as exc:
_logger.error(f"Errore scheduler: {exc}")
# ── Funzioni Pubbliche ────────────────────────────────────────────────────
async def sync_memory(session_id: str) -> Dict[str, Any]:
"""Sincronizza memoria."""
return await _sync_manager.sync_memory(session_id)
async def sync_audit(event: Dict[str, Any]) -> Dict[str, Any]:
"""Sincronizza audit."""
return await _sync_manager.sync_audit(event)
async def distribute_task(task: Dict[str, Any]) -> Dict[str, Any]:
"""Distribuisce task a Nodo E."""
return await _sync_manager.distribute_task_to_oracle(task)
async def get_sync_stats() -> Dict[str, Any]:
"""Ritorna statistiche sincronizzazione."""
return _sync_manager.sync_stats