"""TTL 캐시 — 프로세스 메모리에만 있다. rate_limit 과 같은 한계를 갖는다. ★ 두는 이유는 속도가 아니라 **차단**이다. 공개 검색 1회가 네이버를 최대 3번 긁는데 (넓은 검색 1 + 겨냥 2), 인증 없는 경로라 새로고침만으로도 나간다. 실측(2026-09-03): 테스트를 반복하다 m.place.naver.com 에서 429 를 받았다. """ import time from typing import Any, Optional _store: dict[str, tuple[float, Any]] = {} _MAX_KEYS = 500 def get(key: str) -> Optional[Any]: hit = _store.get(key) if not hit: return None if time.monotonic() >= hit[0]: _store.pop(key, None) return None return hit[1] def put(key: str, value: Any, ttl_sec: float) -> None: # 만료된 것부터 버리고, 그래도 넘치면 가장 먼저 만료될 것을 버린다. if len(_store) >= _MAX_KEYS: now = time.monotonic() for k in [k for k, (exp, _) in _store.items() if exp <= now]: _store.pop(k, None) if len(_store) >= _MAX_KEYS: _store.pop(min(_store, key=lambda k: _store[k][0]), None) _store[key] = (time.monotonic() + ttl_sec, value) def clear() -> None: _store.clear()