from __future__ import annotations import time from collections import OrderedDict from threading import Lock class MessageDeduplicator: TTL_SECONDS = 60.0 def __init__(self, max_size: int = 1000): self._max_size = max_size self._cache: OrderedDict[str, float] = OrderedDict() self._lock = Lock() def is_duplicate(self, message_id: str) -> bool: now = time.monotonic() with self._lock: if message_id in self._cache: ts = self._cache[message_id] if now - ts < self.TTL_SECONDS: return True del self._cache[message_id] self._cache[message_id] = now self._cache.move_to_end(message_id) if len(self._cache) > self._max_size: self._cleanup_expired(now) return False def mark_seen(self, message_id: str) -> None: with self._lock: self._cache[message_id] = time.monotonic() self._cache.move_to_end(message_id) if len(self._cache) > self._max_size: self._cleanup_expired(time.monotonic()) def _cleanup_expired(self, now: float) -> None: expired = [k for k, ts in self._cache.items() if now - ts >= self.TTL_SECONDS] for k in expired: del self._cache[k] def __len__(self) -> int: with self._lock: return len(self._cache)