Spaces:
Sleeping
Sleeping
| """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()) | |