[5주차] RateLimit 수정 및 테스트 코드 작성#105
Conversation
|
|
||
| public RateLimitExceedException(String message) { | ||
| super(message); | ||
| this.httpStatus = HttpStatus.TOO_MANY_REQUESTS; // 429 상태 코드 |
| return new RateLimitResponseDto<>(429, "RATE_LIMIT_EXCEEDED", "요청 제한 횟수를 초과했습니다.", null); | ||
| } |
There was a problem hiding this comment.
요청 제한과 관련해서 적절한 response 코드를 사용해 주셨네요!
status 코드 외에도 custom 코드를 작성해 주셔서 클라이언트에서 파악하기 졸을 것 같습니다!
| private static final int REQUEST_LIMIT = 50; | ||
| private static final int BLOCK_HOURS = 1; | ||
| private static final int TIME_MINUTE = 60; |
There was a problem hiding this comment.
"조회 API 에 RateLimit 을 적용합니다. 비정상적 사용 패턴을 감지하고 시스템을 보호하기 위해 1분 내 50회 이상 요청 시 1시간 동안 해당 IP 를 차단합니다."
이 요구 사항에 맞춰 구현 하신 것 같은데요 TimeMinute는 1분을 고려 해서 선정하신 걸까요? 만약 60이 60초를 의미한다면 변수명을 수정하시는 것이 좋습니다!
| // 51번째 요청은 차단되어야 함 | ||
| boolean finalResult = rateLimitInterceptor.preHandle(request, response, handlerMethod); | ||
| assertFalse(finalResult, "51번째 요청 차단 실패"); | ||
|
|
||
| // 응답이 429 상태 코드인지 확인 | ||
| verify(response).setStatus(HttpStatus.TOO_MANY_REQUESTS.value()); | ||
|
|
||
| // 응답 본문을 JSON으로 변환하여 검증 | ||
| responseWriter.flush(); // PrintWriter 내용을 보장 | ||
| String jsonResponse = responseWriter.toString(); | ||
| System.out.println("Response Body: " + jsonResponse); // 디버깅 메시지 | ||
| RateLimitResponseDto<?> actualResponse = objectMapper.readValue(jsonResponse, RateLimitResponseDto.class); |
There was a problem hiding this comment.
요청 차단 부터 응답 코드까지 검증해 주셨네요! 훌륭합니다! 👍
There was a problem hiding this comment.
현재 코드에는 동시에 요청이 왔을때 RateLimiter가 제대로 작동하는지에 대한 테스트코드가 없는데요.
이부분을 추가해주시면 더 서버가 더 견고해질거에요! 추가 하시는 것을 추천 드립니다!
| } | ||
|
|
||
| @Test | ||
| void RateLimit_초과시_예약_차단() { |
There was a problem hiding this comment.
Rate Limiter가 동시 요청이 있을 시에도 잘 작동하는지와 관련된 테스트 코드를 하나 더 작성해보세요!
There was a problem hiding this comment.
테스트 코드를 꼼꼼하게 작성해 주셨네요!
현재 validation 조건 별로 작성해 주신 것으로 보이는데요. 실제로 꼼꼼하게 validation이 작동하는지 확인하는것은 테스트 코드에서 중요한 부분입니다! 잘 작성해 주셨어요!
| Theater theater1 = new Theater("Theater1"); | ||
|
|
||
| screening = new Screening(movie1, theater1, LocalTime.now()); | ||
|
|
||
| Users user1 = new Users("user1", 20); | ||
|
|
||
| reservation = new Reservation(user1, screening); | ||
|
|
||
| Seat seat1 = new Seat(theater1, "A", 1, reservation); | ||
| Seat seat2 = new Seat(theater1, "A", 2, reservation); |
There was a problem hiding this comment.
테스트 데이터가 중복된다면 java-test-fixtures를 사용해보시는 것을 추천 드립니다.
테스트 데이터를 Fixture로 관리하고, 다른 모듈에서 이를 가져와 활용할 수 있어 중복 코드가 줄어듭니다!
| "local key = KEYS[1]\n" + | ||
| "local ttl = tonumber(redis.call('TTL', key))\n" + | ||
| "if ttl > 0 then\n" + | ||
| " return ttl\n" + // TTL이 남아 있으면 반환 | ||
| "end\n" + | ||
| "redis.call('SET', key, 1, 'EX', 300)\n" + //TTL 설정 (5분) | ||
| "return 0"; |
There was a problem hiding this comment.
Lua Script 는 따로 파일로 관리하시는 것이 유지 보수 하기 편합니다!
|
5주차 까지 고생 많으셨습니다! 🙏 좋았던 점
아쉬운 점
리뷰 포인트→ 코드 리뷰에 작성해 두었습니다. 기타 질문
주차별 과제 중 빠진 부분이 있다면 추가로 구현해 보시는 것을 추천드립니다. 그러면 프로젝트의 완성도가 한층 더 높아질 거에요!💡 |
제목(title)
작업 내용
발생했던 문제와 해결 과정을 남겨 주세요.
이번 주차에서 고민되었던 지점이나, 어려웠던 점을 알려 주세요.
리뷰 포인트
기타 질문
다른 분들처럼 계층별 멀티 모듈로 구조를 바꾸는 게 좋을까요?
마지막까지 추가로 리뷰해 주셔서 감사합니다! 많이 부족하겠지만 열심히 배우겠습니다!