📌 Description
McpRateLimiter(backend/src/main/java/com/opensource/docgrid/domain/mcp/security/McpRateLimiter.java)의
windows 맵(ConcurrentHashMap<String, Window>, key = "userId:toolName")은 한 번 등록된 조합을
절대 remove()하지 않는다. 60초가 지나면 Window.count는 다음 호출 때 리셋되지만, Window 객체와
그 키는 서버가 재시작되기 전까지 맵에 영구히 남는다.
🔍 문제 상황
사용자 수 × 도구 종류(3종) 조합만큼 맵이 계속 커지기만 하고 절대 줄어들지 않는 구조 — 흔히 말하는
메모리 누수 패턴이다.
#117 설계 문서(docs/design/kangcheolung-#117-rate-limiting-output-sanitization.md)의
"남은 이슈"에 이미 알려진 한계로 기록돼 있음: "TTL 기반 정리(eviction)는 이번 MVP 범위에서
하지 않음, 필요성이 생기면 별도 검토."
- MVP 단계라 사용자 수가 적어
Window 객체(필드 2개, 몇십 바이트) 수준의 메모리 영향은
현재는 무시할 만함. 사용자가 수만 단위로 늘면 결국 문제가 될 수 있음.
✅ To-do
✅ 완료 기준
📒 기타
#117 설계 문서에 이미 명시된 한계를 재확인·정리한 것. 신규 발견 아님.
- 관련 메모리:
project_mcp_rate_limiter_unbounded_map.md
📌 Description
McpRateLimiter(backend/src/main/java/com/opensource/docgrid/domain/mcp/security/McpRateLimiter.java)의windows맵(ConcurrentHashMap<String, Window>, key ="userId:toolName")은 한 번 등록된 조합을절대
remove()하지 않는다. 60초가 지나면Window.count는 다음 호출 때 리셋되지만,Window객체와그 키는 서버가 재시작되기 전까지 맵에 영구히 남는다.
🔍 문제 상황
사용자 수 × 도구 종류(3종) 조합만큼 맵이 계속 커지기만 하고 절대 줄어들지 않는 구조 — 흔히 말하는
메모리 누수 패턴이다.
#117설계 문서(docs/design/kangcheolung-#117-rate-limiting-output-sanitization.md)의"남은 이슈"에 이미 알려진 한계로 기록돼 있음: "TTL 기반 정리(eviction)는 이번 MVP 범위에서
하지 않음, 필요성이 생기면 별도 검토."
Window객체(필드 2개, 몇십 바이트) 수준의 메모리 영향은현재는 무시할 만함. 사용자가 수만 단위로 늘면 결국 문제가 될 수 있음.
✅ To-do
ConcurrentHashMap→ Caffeine 캐시(expireAfterAccess등 TTL 옵션)로 교체McpRateLimiterTest의 동시성 테스트(50스레드, 윈도우 만료 경계 레이스)가 여전히 통과하는지 확인✅ 완료 기준
./backend/gradlew -p backend test전체 통과.📒 기타
#117설계 문서에 이미 명시된 한계를 재확인·정리한 것. 신규 발견 아님.project_mcp_rate_limiter_unbounded_map.md