Pablo
ContextForge v0.1.0 - shared context compiler for multi-agent LLM systems
6d9c72b
raw
history blame
2.36 kB
"""TTL-based eviction cache for stale contexts."""
import asyncio
import logging
from datetime import datetime, timedelta
from typing import Any
logger = logging.getLogger(__name__)
class TTLCache:
"""Thread-safe TTL cache with automatic eviction."""
def __init__(self, default_ttl_seconds: int = 300):
self._store: dict[str, tuple[Any, datetime]] = {}
self._lock = asyncio.Lock()
self._default_ttl = default_ttl_seconds
async def set(self, key: str, value: Any, ttl_seconds: int | None = None) -> None:
"""Store a value with optional custom TTL."""
ttl = ttl_seconds if ttl_seconds is not None else self._default_ttl
expiry = datetime.now() + timedelta(seconds=ttl)
async with self._lock:
self._store[key] = (value, expiry)
async def get(self, key: str) -> Any | None:
"""Retrieve a value if it exists and is not expired."""
async with self._lock:
if key not in self._store:
return None
value, expiry = self._store[key]
if datetime.now() > expiry:
del self._store[key]
return None
return value
async def delete(self, key: str) -> bool:
"""Delete a key, returns True if it existed."""
async with self._lock:
if key in self._store:
del self._store[key]
return True
return False
async def evict_expired(self) -> int:
"""Remove all expired entries, returns count evicted."""
count = 0
now = datetime.now()
async with self._lock:
expired = [k for k, (_, exp) in self._store.items() if now > exp]
for k in expired:
del self._store[k]
count += 1
if count > 0:
logger.info(f"Evicted {count} expired entries from TTL cache")
return count
async def clear(self) -> None:
"""Clear all entries."""
async with self._lock:
self._store.clear()
async def size(self) -> int:
"""Return current entry count."""
async with self._lock:
return len(self._store)
async def keys(self) -> list[str]:
"""Return all current keys."""
async with self._lock:
return list(self._store.keys())