"""IP 단위 호출 제한 — 프로세스 메모리에만 있는 아주 단순한 것. ★ 한계를 먼저 적는다. 프로세스가 여럿이면 한도가 그 수만큼 곱해지고, 재시작하면 리셋된다. 제대로 하려면 앞단(nginx `limit_req`)이나 공유 저장소가 필요하다. ★ 그런데도 두는 이유: 이걸 쓰는 곳이 **인증 없이 유료 외부 API 를 부르는 경로**다. 방어가 0 이면 새로고침을 누르고 있는 것만으로 요금이 나간다 (카카오 키워드 검색은 무료 한도를 넘기면 건당 2원 — services/external/kakao.py 주석). """ import time from collections import defaultdict, deque _hits: dict[str, deque] = defaultdict(deque) def allow(key: str, limit: int, window_sec: float) -> bool: """key 가 window_sec 안에서 limit 번을 넘지 않았으면 True(그리고 1회로 센다).""" now = time.monotonic() bucket = _hits[key] while bucket and now - bucket[0] > window_sec: bucket.popleft() if len(bucket) >= limit: return False bucket.append(now) # 안 쓰는 키가 쌓이는 걸 막는다. 호출이 뜸하면 자연히 비워진다. if not bucket: _hits.pop(key, None) return True def reset(): """테스트 전용 — 프로세스 상태를 비운다.""" _hits.clear()