[4주차] RateLimit 적용 및 테스트코드 추가#89
Conversation
|
안녕하세요! 이번 주차도 과제 하시느라 고생 많으셨습니다! |
| local key = KEYS[1] --[[ 요청 카운트 키 ]] | ||
| local blockKey = KEYS[2] --[[ 차단된 IP 키 ]] | ||
| local maxRequests = tonumber(ARGV[1]) --[[ 최대 요청 횟수 (초) ]] | ||
| local expireTime = tonumber(ARGV[2]) --[[ 요청 카운트 만료 시간 (초) ]] | ||
| local blockTime = tonumber(ARGV[3]) --[[ 차단 시간 (초) ]] | ||
|
|
||
| --[[ 차단 여부 확인 ]] | ||
| if redis.call("exists", blockKey) == 1 then return 0 end | ||
|
|
||
| --[[ 요청 카운트 증가 및 만료 시간 설정 ]] | ||
| local count = redis.call("incr", key) | ||
| if count == 1 then redis.call("expire", key, expireTime) end | ||
|
|
||
| --[[ 요청 제한 초과 시 차단 ]] | ||
| if count > maxRequests then | ||
| redis.call("setex", blockKey, blockTime, "BLOCKED") | ||
| return 0 | ||
| end | ||
|
|
||
| return 1 No newline at end of file |
There was a problem hiding this comment.
요구사항을 정확하게 반영해서 Lua Script를 구현해 주셨군요!
'1분 내 50회 이상 요청 시 1시간 동안 해당 IP를 차단'하는 부분도 요구사항에 맞춰 잘 구현해 주셨어요!
| if (!redisRateLimitPort.isAllowed(ip)) { | ||
| return ApiResponse.of("너무 많은 요청으로 조회가 차단되었습니다. ", HttpStatusCode.TOO_MANY_REQUESTS); | ||
| } |
There was a problem hiding this comment.
조회 제한시 응답을 적절하게 구현하셨네요! isAllowed(ip)는 RateLimiter를 통해 조회를 제한하는 부분이므로 , 429 TOO_MANY_REQUESTS 응답을 반환하는 방식이 적절합니다!
다만 현재는 CustomError코드는 따로 설정하지 않으신 것으로 보이는데요, 클라이언트와 통신시 에러를 특정하기 위해서는 CustomCode를 구현하시는 것도 좋은 방법입니다.
There was a problem hiding this comment.
혹시 CustomError코드를 사용하게 된다면 http헤더의 상태코드는 그대루 두고 내부 메시지를 통해서 해당 코드값을 표현하는 식으루 CustomCode를 구현 하면 될까요!?!
There was a problem hiding this comment.
@rmsxo200
네 맞습니다. 헤더의 상태코드는 그대로 두고 내부 메세지 혹은 지금 사용하고 계신 ApiResponse에 필드를 하나 더 추가 해 구현하시는 것이 좋아요!
There was a problem hiding this comment.
Stubbing에 대해 질문해 주셨는데요. 충분히 궁금하실 수 있는 부분이라고 생각합니다.
이미 정해진 결과를 검증하는 느낌이 들 수도 있으니까요.
몇가지 장점이 있는데 제가 느끼는 것을 적어보면
- 컨트롤러 테스트에서 비즈니스 로직을 실행하지 않고, 요청과 응답 형식 검증을 위해 사용할 수 있어요. 특히 저희 회사 에서는 RestDocs을 활용할때 이 장점이 드러나는 것 같아요 .
- 데이터베이스를 사용하지 않고 서비스 레이어에서 일부분의 작동만 확인하기 위해 간편히 사용하기 좋습니다.
- 외부 API를 활용하는 로직에도 직접 호출하지 않고 사용하는 장점이 있죠
Stubbing이 '끼워 맞추는 것 같다'는 느낌이 들 수도 있지만, 독립적인 테스트를 도와주는 효과적인 방법중 하나라고 생각합니다!
There was a problem hiding this comment.
많은 장점이 있는 것 같습니다!
앞으로 테스트코드를 열심히 작성하도록 하겠습니다!
| // 예매 성공 후 Redis 제한 설정 | ||
| redisRateLimitPort.setReservationLimit(scheduleId, memberId); | ||
|
|
There was a problem hiding this comment.
5분에 한개씩 예매를 제한 하는 것도 요구사항에 맞춰 구현해 주셨네요! 성공후에 제한 설정 + 예매 전 확인 까지 잘 구현해 주셨어요!
| @AutoConfigureMockMvc | ||
| @Testcontainers // TestContainers 사용 | ||
| @Transactional | ||
| @Sql(scripts = "/sql/reservationTest.sql") // SQL 파일 실행 |
There was a problem hiding this comment.
통합테스트 구현을 깔끔하게 해주셨네요. sql로 실제 데이터를 넣어주셔서 실 환경과 비슷하게 구현해주셨네요! 훌륭합니다!
| mockMvc.perform(post("/api/v1/movie-reservation") | ||
| .contentType(MediaType.APPLICATION_JSON) | ||
| .content(objectMapper.writeValueAsString(requestDto))) | ||
| .andExpect(status().isCreated()); | ||
|
|
||
| // 5분 내 동일한 요청을 보내면 예외 발생 확인 | ||
| mockMvc.perform(post("/api/v1/movie-reservation") | ||
| .contentType(MediaType.APPLICATION_JSON) | ||
| .content(objectMapper.writeValueAsString(requestDto))) | ||
| .andExpect(status().isTooManyRequests()) | ||
| .andExpect(jsonPath("$.message").value("동일 시간대 영화 예매는 5분 후 가능합니다.")); |
There was a problem hiding this comment.
RateLimiter가 걸렸을때 Too Many Request가 반환되는지 확인하는 코드도 테스트로 작성해 주셨네요! 👍
다만, 현재는 여러사용자가 동시에 요청했을때 RateLimiter가 작동하는 지는 검증하고 있지 않은것 같습니다.
통합테스트에 이부분도 같이 고려해주시면 더 완성도 높은 코드가 될것 같아요!
| id("java") | ||
| id("org.springframework.boot") version "3.4.1" | ||
| id("io.spring.dependency-management") version "1.1.7" | ||
| id("java-test-fixtures") // 테스트 픽스처 활성화 |
There was a problem hiding this comment.
텍스트 픽스처를 활용해주셨네요! 놓치기 쉬운 부분인데 세심하게 구현해 주셨어요!
| @DisplayName("[통합] 회원당 예매 좌석 개수 초과시 예외 발생 테스트") | ||
| void saveMovieReservationSeatLimitExceeded() throws Exception { | ||
| //테스트 sql에서 미리 넣어둔 예매데이터 + 추가로 5좌석 예매 | ||
| MovieReservationRequestDto invalidRequest = TestDataFactory.createMovieReservationRequestDto(5); |
There was a problem hiding this comment.
직접 객체를 생성하는 대신 TestDataFactory를 활용하셨네요. 코드에서 유지보수성을 고민하신게 느껴집니다! 👍
좋았던 점
아쉬운 점
리뷰포인트
추가 질문
4주 동안 정말 고생 많으셨습니다! 🙌 |
|
고생하셨습니다! |
작업 내용
발생했던 문제와 해결 과정을 남겨 주세요.
이번 주차에서 고민되었던 지점이나, 어려웠던 점을 알려 주세요.
리뷰 포인트
기타 질문
테스트 코드는 예매 관련 컨트롤러와 서비스 로직에 대해서만 작성 하였습니다.
조회 로직, 도메인 계층 등 테스트 코드가 누락된 부분이 많지만 리뷰 부탁 드립니다 !