Skip to content

[Refactor] 비동기 안정화#480

Open
dev-dino22 wants to merge 13 commits intofront/devfrom
refactor/466-비동기-안정화

Hidden character warning

The head ref may contain hidden characters: "refactor/466-\ube44\ub3d9\uae30-\uc548\uc815\ud654"
Open

[Refactor] 비동기 안정화#480
dev-dino22 wants to merge 13 commits intofront/devfrom
refactor/466-비동기-안정화

Conversation

@dev-dino22
Copy link
Copy Markdown
Contributor

@dev-dino22 dev-dino22 commented Mar 15, 2026

Issue Number

#466

안녕하세요!
급한대로 짜두었던 코드를 좀 더 정돈해서 문서화까지 완료되어 PR 올립니다🥹

rate limit 관련 문서 정리: https://mint-scissor-943.notion.site/rate-limit-3220c7355c2a802d8abaf2b9cbaa1405?source=copy_link

As-Is

클라이언트에서의 예기치 못한 무한루프 등, 짧은 시간에 동일한 API 요청이 수십회 반복될 경우 사용자에게 적절한 피드백을 하고 상황을 종료 시켜 서버 부담을 줄입니다. 빠른 대응을 위해 에러 모니터링을 구축합니다.

To-Be

  • 백엔드 429 에러 상태코드 대응 메세지 및 에러바운더리 작성
  • 클라이언트 rate limiter 구현
  • 슬라이딩 윈도우 알고리즘으로 최신 5초 API 요청 목록 관리
  • 테스트 코드 작성
  • TooManyRequestError 페이지 작성
    • 사용자 피드백 Sentry 폼 추가
  • 문제 상황 Sentry 보고
  • apiClient 에 에러 타입 및 ClientRateLimitError 커스텀 에러 추가

설계 요약

목적

  • 클라이언트 rate limit: 동일 API를 짧은 시간에 과도하게 호출할 때 요청을 막고, 사용자를 에러 페이지로 이동.
  • 서버 429: 응답 수신 시 Sentry에 보고.
  • Sentry: 발생 페이지, 문제된 API, 클라이언트/서버 구분, (클라이언트 시) store 스냅샷을 보고.

파일별 역할

apis/rateLimit/slidingWindow.ts

  • 역할: 슬라이딩 윈도우 알고리즘의 순수 계산 함수만 제공.
  • 내용:
    • pruneOutsideWindow: 윈도우 밖 타임스탬프 제거.
    • isWithinLimit: 윈도우 내 개수로 허용 여부 판단.
    • appendTimestamp: 윈도우 밖 제거 후 타임스탬프 추가 (불변).
  • 특징: 부수 효과 없음, 테스트 용이.

apis/rateLimit/rateLimiter.ts

  • 역할: 싱글톤에 가까운 단일 모듈. 한도(윈도우·최대 횟수), 적용 대상 정책, 호출된 API별 타임스탬프를 계산·기록·관리.
  • 내용:
    • 정책 상수: RATE_LIMIT_WINDOW_MS, RATE_LIMIT_MAX_COUNT, RATE_LIMIT_ENABLED_BY_METHOD, SKIP_LIST.
    • store: Map<key, number[]> — 키별 타임스탬프 배열 (key = method\nendPoint).
    • 메서드: tryAcquire(method, endPoint, options?, now?) — 적용 대상이면 체크 후 기록, 초과 시 false 반환.
    • 보고용: getSnapshotForReporting(method, endPoint) — 해당 키의 타임스탬프 배열 복사본 반환 (Sentry용).
  • 특징: 모든 API 요청이 이 모듈 하나를 통해 제한되며, 페이지 이동 후에도 store는 유지됨.

apis/apiClient.ts

  • 역할: 실제 HTTP 요청을 보내기 직전에 rate limit 적용, 초과 시 Sentry 보고 후 리다이렉트만 수행 (에러 throw 없음).
  • 내용:
    • requestApi 진입 시 rateLimiter.tryAcquire(method, endPoint, options) 호출.
    • 초과 시: getSnapshotForReportingmonitor.reportClientRateLimitErrorwindow.location.replace(TOO_MANY_REQUESTS) → pending Promise 반환 (fetch 미실행).
    • 서버 429 시: monitor.reportServerTooManyRequest 호출 후 기존대로 ApiError throw.
  • 특징: 개별 API/훅에 에러 분기 추가 없이, apiClient 한 곳에서만 처리.

shared/utils/monitor.ts (monitor)

  • 역할: Rate limit 관련 Sentry 보고만 담당 (클라이언트 초과 / 서버 429).
  • 내용:
    • reportClientRateLimitError(method, endPoint, timestamps): 태그 rate_limit_source: client, Extra에 page, api_method, api_endpoint, rate_limit_timestamps, rate_limit_request_count.
    • reportServerTooManyRequest(method, endPoint, serverMessage?): 태그 rate_limit_source: server, Extra에 page, api_method, api_endpoint, (선택) server_message.
  • 특징: window.location으로 현재 페이지 계산, Sentry에만 의존.

흐름 요약

  1. 요청 시: apiClientrateLimiter.tryAcquire (slidingWindow 로직 사용).
  2. 클라이언트 초과: tryAcquire false → 스냅샷 수집 → Sentry 보고 → window.location.replace → 요청 중단.
  3. 서버 429: fetch 응답 429 → Sentry 보고 → ApiError throw.

에러 페이지

  • 경로: ROUTE_PATH.TOO_MANY_REQUESTS (/error/too-many-requests).
  • 역할: 안내 문구, 새로고침 버튼, (필요 시) Sentry 연동. window.location.replace로 진입하므로 SPA 상태 초기화.

Check List

  • 빌드, 테스트가 전부 통과되었나요?
  • merge할 branch를 확인했나요?
  • Assignee를 지정했나요?
  • Label을 지정했나요?

(Optional) Additional Description

현재 의사 결정을 논의할 부분을 정리하면,

  • rate limit 적용은 GET 요청만
  • 5초 내 20번 이상의 동일한 API GET 요청을 무한루프로 간주
    입니다!

각 이유는 문서에 정리해두었어요!

코드에 있는 설명 주석은 PR 피드백 완료되면 제거한 후 머지하겠습니다!

감사합니다 ㅎㅎ

@dev-dino22 dev-dino22 self-assigned this Mar 15, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 15, 2026

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 3afbe74a-9357-44e4-845f-3c12ba212343

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch refactor/466-비동기-안정화
📝 Coding Plan
  • Generate coding plan for human review comments

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Tip

You can enable review details to help with troubleshooting, context usage and more.

Enable the reviews.review_details setting to include review details such as the model used, the time taken for each step and more in the review comments.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant