[feat][queue-service] Server-driven Adaptive Polling 도입#35
Conversation
- 응답 DTO 에 retryAfterMs 필드 추가 - PollingIntervalPolicy 클래스 추가 (Presentation 레이어) - 순번별 차등 폴링 간격 (1초 / 5초 / 15초 / 30초) - Jitter 적용으로 동시 요청 분산 - Controller 에서 Policy 주입 및 응답 생성 - 테스트 코드 + RestDocs 갱신 - 부하 테스트 스크립트 (k6) 추가: before/after 비교 Related to #34
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository: first-ticket/coderabbit/.coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
📝 WalkthroughWalkthrough이 PR은 서버 권장 폴링 간격을 응답에 포함하는 Adaptive Polling 기능을 구현합니다. 큐 위치별 동적 계산 정책, 응답 계약 변경, 컨트롤러 통합, API 문서화, 부하 테스트 스크립트, 그리고 테스트 커버리지를 함께 업데이트합니다. ChangesAdaptive Polling Implementation
Sequence DiagramsequenceDiagram
participant Client as 클라이언트
participant Controller as QueueTokenController
participant Policy as PollingIntervalPolicy
participant Response as QueueTokenResponse
Client->>Controller: POST /api/v1/queues/programs/{id}
Controller->>Controller: 프로그램 큐 enqueue 처리
Controller->>Policy: nextRetryAfterMs(position)
Policy-->>Controller: 계산된 retryAfterMs 반환
Controller->>Response: from(result, retryAfterMs)
Response-->>Controller: 응답 객체 생성
Controller-->>Client: 200 OK {position, retryAfterMs, ...}
Client->>Client: retryAfterMs 밀리초 대기
Client->>Controller: GET /api/v1/queues/programs/{id}
Controller->>Controller: 토큰 상태 조회
Controller->>Policy: nextRetryAfterMs(position)
Policy-->>Controller: 계산된 retryAfterMs 반환
Controller->>Response: from(result, retryAfterMs)
Response-->>Controller: 응답 객체 생성
alt WAITING 상태
Controller-->>Client: {position, retryAfterMs, ...}
Client->>Client: retryAfterMs 밀리초 대기
else ADMITTED 상태
Controller-->>Client: {entryToken, retryAfterMs: null, ...}
Client->>Client: 폴링 중단, entryToken으로 입장
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested labels
Suggested reviewers
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (3)
scripts/after.js (2)
22-26: ⚡ Quick winAdaptive 시나리오도
enqueue성공을 체크해 주세요.Line 22-26에서 enqueue 결과 검증이 없어, 진입 실패 상황이 동적 폴링 효과 측정에 섞일 수 있습니다.
제안 diff
- http.post( + const enqueueRes = http.post( `${BASE_URL}/api/v1/queues/programs/${PROGRAM_ID}`, null, { headers: { 'X-User-Id': userIdsByVU[__VU] }, tags: { name: 'enqueue' } } ); + check(enqueueRes, { 'enqueue 201': (r) => r.status === 201 });🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@scripts/after.js` around lines 22 - 26, The current http.post call that enqueues programs (the expression using BASE_URL, PROGRAM_ID, userIdsByVU[__VU], tags: { name: 'enqueue' }) does not verify success; update the code to capture the response from http.post, check its HTTP status (e.g., 200/201 or expected success code) and/or response body for an enqueue success indicator, and handle failures by recording/logging the error and failing the VU iteration (or incrementing a failure metric) so adaptive scenario runs don't mix entry failures into performance measurements; ensure the check surrounds the same http.post invocation and uses the same identifiers (BASE_URL, PROGRAM_ID, userIdsByVU, __VU, tags: { name: 'enqueue' }).
44-46: ⚡ Quick win
retryAfterMs값의 하한 검증을 추가해 과도한 루프를 방지해 주세요.Line 44-46에서 0 이하/비정상 값이 들어오면 즉시 재요청 루프가 발생할 수 있어, 기본값(3초) 폴백 조건을 두는 편이 안전합니다.
제안 diff
- if (retryAfterMs != null) { + if (typeof retryAfterMs === 'number' && retryAfterMs > 0) { sleepSec = retryAfterMs / 1000; }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@scripts/after.js` around lines 44 - 46, The current assignment of sleepSec from retryAfterMs (retryAfterMs -> sleepSec) can produce immediate/very short loops if retryAfterMs is 0, negative, or non-numeric; modify the logic around retryAfterMs so you validate its lower bound and fall back to a safe default (e.g., 3000 ms / 3 sec) when retryAfterMs is null/undefined, <= 0, or NaN, then set sleepSec = validatedRetryAfterMs / 1000; ensure you reference and update the same variables (retryAfterMs and sleepSec) and keep the default value constant for readability.scripts/before.js (1)
25-29: ⚡ Quick win
enqueue응답도 검증해서 기준(Before) 지표 신뢰도를 보장해주세요.Line 25-29에서 enqueue 성공 여부를 확인하지 않으면, 초기 진입 실패가 폴링 결과에 섞여 Before/After 비교가 왜곡될 수 있습니다.
제안 diff
- http.post( + const enqueueRes = http.post( `${BASE_URL}/api/v1/queues/programs/${PROGRAM_ID}`, null, { headers: { 'X-User-Id': userIdsByVU[__VU] }, tags: { name: 'enqueue' } } ); + check(enqueueRes, { 'enqueue 201': (r) => r.status === 201 });🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@scripts/before.js` around lines 25 - 29, 현재 http.post call that enqueues the program (the call using BASE_URL, PROGRAM_ID, userIdsByVU[__VU], tag 'enqueue') does not validate the response; ensure you capture the response from http.post, check the HTTP status (e.g., status >=200 && status <300) and/or response body for success, and if it is not successful log the response details and fail/exit or throw so the before step does not silently continue; add this validation immediately after the http.post invocation and include the request context (PROGRAM_ID, __VU) in the log.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@src/test/java/com/firstticket/queueservice/queuetoken/presentation/QueueTokenControllerTest.java`:
- Line 109: The test docs mark data.retryAfterMs as optional but it is always
present for a successful queue-token-issue (WAITING) response; locate the
fieldWithPath("data.retryAfterMs") call in QueueTokenControllerTest and remove
the .optional() so the field is documented as required (keep the same
description text), ensuring the contract reflects the actual response.
---
Nitpick comments:
In `@scripts/after.js`:
- Around line 22-26: The current http.post call that enqueues programs (the
expression using BASE_URL, PROGRAM_ID, userIdsByVU[__VU], tags: { name:
'enqueue' }) does not verify success; update the code to capture the response
from http.post, check its HTTP status (e.g., 200/201 or expected success code)
and/or response body for an enqueue success indicator, and handle failures by
recording/logging the error and failing the VU iteration (or incrementing a
failure metric) so adaptive scenario runs don't mix entry failures into
performance measurements; ensure the check surrounds the same http.post
invocation and uses the same identifiers (BASE_URL, PROGRAM_ID, userIdsByVU,
__VU, tags: { name: 'enqueue' }).
- Around line 44-46: The current assignment of sleepSec from retryAfterMs
(retryAfterMs -> sleepSec) can produce immediate/very short loops if
retryAfterMs is 0, negative, or non-numeric; modify the logic around
retryAfterMs so you validate its lower bound and fall back to a safe default
(e.g., 3000 ms / 3 sec) when retryAfterMs is null/undefined, <= 0, or NaN, then
set sleepSec = validatedRetryAfterMs / 1000; ensure you reference and update the
same variables (retryAfterMs and sleepSec) and keep the default value constant
for readability.
In `@scripts/before.js`:
- Around line 25-29: 현재 http.post call that enqueues the program (the call using
BASE_URL, PROGRAM_ID, userIdsByVU[__VU], tag 'enqueue') does not validate the
response; ensure you capture the response from http.post, check the HTTP status
(e.g., status >=200 && status <300) and/or response body for success, and if it
is not successful log the response details and fail/exit or throw so the before
step does not silently continue; add this validation immediately after the
http.post invocation and include the request context (PROGRAM_ID, __VU) in the
log.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository: first-ticket/coderabbit/.coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: b49d6b1b-3124-485a-80ea-090502a598f5
📒 Files selected for processing (7)
scripts/after.jsscripts/before.jssrc/docs/asciidoc/index.adocsrc/main/java/com/firstticket/queueservice/queuetoken/presentation/PollingIntervalPolicy.javasrc/main/java/com/firstticket/queueservice/queuetoken/presentation/QueueTokenController.javasrc/main/java/com/firstticket/queueservice/queuetoken/presentation/dto/QueueTokenResponse.javasrc/test/java/com/firstticket/queueservice/queuetoken/presentation/QueueTokenControllerTest.java
🌱 설명
응답 DTO 에
retryAfterMs필드를 추가하여 Server-driven Adaptive Polling 도입.서버가 사용자 순번에 따라 폴링 간격을 동적으로 제어하여 1:N fan-out 구조의 대기열에서 폴링 부하를 효율적으로 분산.
PollingIntervalPolicy클래스 추가 (Presentation 레이어)QueueTokenResponse에retryAfterMs필드 추가QueueTokenController에서 Policy 주입 및 응답 생성📌 관련 이슈
💻 커밋 유형
📝 체크리스트
📚 추가 설명
API 응답 변경
Before
{ "tokenId": "...", "status": "WAITING", "issuedAt": "...", "position": 234 }After
{ "tokenId": "...", "status": "WAITING", "issuedAt": "...", "position": 234, "retryAfterMs": 5300 }ADMITTED 등 큐에서 빠진 상태(position = null)에서는
retryAfterMs = null→@JsonInclude(NON_NULL)로 응답에서 제외됨 (클라이언트 폴링 종료 신호).부하 테스트 결과 (k6, Vuser 3000, Duration 3분)
폴링 부하 1/3 감소, 응답시간 65% 이상 개선 확인.
Summary by CodeRabbit
릴리스 노트
New Features
retryAfterMs필드 추가 - 서버가 권장하는 다음 폴링 대기 시간을 동적으로 제공합니다.Documentation