-
Notifications
You must be signed in to change notification settings - Fork 0
[Quiz][Refactor] 제미나이 SDK 타임아웃 및 재시도 설정 #206
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 1 commit
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
126 changes: 126 additions & 0 deletions
126
docs/feature_description/GEMINI_TIMEOUT_AND_RETRY_STRATEGY.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,126 @@ | ||
| # Gemini SDK 타임아웃 및 재시도 전략 (Timeout & Retry Strategy) | ||
|
|
||
| ## 1. 개요 (Overview) | ||
| 본 문서는 Google Gemini API 연동 시 안정성을 확보하기 위해 적용한 **타임아웃(Timeout)** 및 **재시도(Retry)** 정책의 수립 과정과 최종 구현 내용을 상세히 기술합니다. | ||
|
|
||
| --- | ||
|
|
||
| ## 2. 의사결정 과정 (Decision Logs) | ||
|
|
||
| 우리는 시스템의 **안정성(Stability)**과 **유연성(Flexibility)** 사이에서 최적의 균형을 찾기 위해 다음과 같은 과정을 거쳤습니다. | ||
|
|
||
| ### 2.1 문제 정의 | ||
| - **무한 대기 위험**: 초기 구현에는 SDK에 명시적인 타임아웃 설정이 없었습니다. AI 모델 특성상 응답 생성에 수십 초~수분이 소요될 수 있는데, 네트워크 단절이나 서비스 장애 발생 시 스레드가 무한히 대기(Hang)하여 전체 시스템의 자원을 고갈시킬 위험이 있었습니다. | ||
| - **요청별 특성 차이**: '간단한 채팅 응답'은 10초 내에 끝나야 하지만, '거대 텍스트 기반 퀴즈 생성'은 3분 이상 소요될 수도 있습니다. 이를 하나의 설정으로 묶는 것은 비효율적입니다. | ||
|
|
||
| ### 2.2 대안 검토 및 선택 | ||
|
|
||
| #### ❌ Option 1: 글로벌 타임아웃 (`GeminiClientManager`) | ||
| `Client` 객체를 생성할 때 `HttpOptions`를 주입하여 전역적으로 타임아웃을 고정하는 방식입니다. | ||
| - **장점**: 구현이 매우 간단하며 `application.yml`에서 중앙 관리가 용이합니다. | ||
| - **단점**: 모든 요청에 동일한 타임아웃이 강제됩니다. 짧은 작업과 긴 작업을 구분할 수 없어, 긴 작업에 맞추면 짧은 작업의 장애 감지가 늦어지고, 짧은 작업에 맞추면 긴 작업이 실패합니다. | ||
| - **결과**: **기각 (Too rigid)** | ||
|
|
||
| #### ✅ Option 2: 요청별 타임아웃 (`GeminiRequest` → `GenerateContentConfig`) | ||
| 요청 단위로 타임아웃을 설정하고, 이를 SDK 호출 시점에 주입하는 방식입니다. | ||
| - **장점**: **유연성 극대화**. 호출하는 비즈니스 로직(퀴즈, 채팅 등)의 특성에 맞춰 타임아웃을 동적으로 조절할 수 있습니다. | ||
| - **구현**: | ||
| - `GeminiRequest` DTO에 `timeout` 필드 추가 (Default: 60,000ms). | ||
| - `GeminiSdkClient`에서 `request.getTimeout()` 값을 읽어 `GenerateContentConfig.httpOptions`에 적용. | ||
| - **결과**: **최종 채택 (Selected)** | ||
|
|
||
| --- | ||
|
|
||
| ## 3. 최종 구현 상세 (Implementation) | ||
|
|
||
| ### 3.1 타임아웃 적용 로직 | ||
| - **기본값**: 60초 (1분). 별도 설정 없이 호출하면 이 값이 적용됩니다. | ||
| - **커스텀**: `GeminiRequest.builder().timeout(120000L).build()` 와 같이 밀리초(ms) 단위로 설정 가능. | ||
|
|
||
| ### 3.2 코드 예시 (Java) | ||
| ```java | ||
| // GeminiSdkClient.java | ||
| GenerateContentConfig config = GenerateContentConfig.builder() | ||
| // ... | ||
| .httpOptions(HttpOptions.builder() | ||
| .timeout((int) request.getTimeout()) // Request에서 타임아웃 가져오기 | ||
| .build()) | ||
| .build(); | ||
| ``` | ||
|
|
||
| --- | ||
|
|
||
| ## 4. Gemini SDK 정책 분석 보고서 (Reference) | ||
|
|
||
| > **Note**: 아래 내용은 Google GenAI SDK(Python/Java 공통 사상)의 기본 정책을 분석한 내용입니다. | ||
|
|
||
| ### 4.1 타임아웃(Timeout) 정책 | ||
|
|
||
| #### 기본 타임아웃 설정 | ||
| Gemini SDK의 타임아웃은 `HttpOptions` 클래스의 `timeout` 파라미터로 제어됩니다. | ||
|
|
||
| - **단위**: 밀리초(Milliseconds) | ||
|
|
||
| | 설정값 | 초 단위 | 용도 | | ||
| | :--- | :--- | :--- | | ||
| | **30,000ms** | 30초 | 경량 요청, 빠른 응답 필요 (예: 챗봇 대화) | | ||
| | **60,000ms** | 60초 | **표준 요청 (기본 권장값)** | | ||
| | **600,000ms** | 600초 | 장시간 처리 (예: 대용량 텍스트/이미지/비디오 분석) | | ||
|
|
||
| #### 타임아웃 제약 사항 | ||
| 실제 운영 환경에서 관찰된 제약사항입니다. | ||
| - **상한선**: SDK 또는 API 게이트웨이 레벨에서 약 **600초(10분)** 의 하드 타임아웃이 존재할 수 있습니다. | ||
| - **연결 중단**: 지나치게 긴 요청은 중간 로드밸런서 등에서 연결이 끊길 수 있으므로, 적절한 타임아웃 설정이 필수입니다. | ||
|
|
||
| ### 4.2 재시도(Retry) 정책 | ||
|
|
||
| #### 재시도 설정 구조 (`HttpRetryOptions`) | ||
| SDK는 일시적인 네트워크 오류나 서버 과부하 상황에 대응하기 위해 재시도 메커니즘을 내장하고 있습니다. | ||
|
|
||
| | 파라미터 | 기본값 (Default) | 설명 | | ||
| | :--- | :--- | :--- | | ||
| | `attempts` | **5회** | 최대 재시도 시도 횟수 | | ||
| | `initial_delay` | 1초 | 첫 재시도 전 대기 시간 | | ||
| | `max_delay` | 60초 | 재시도 대기 시간의 최대 상한 | | ||
| | `exp_base` | 2 | 지수 백오프(Exponential Backoff) 승수 | | ||
|
|
||
| #### 지수 백오프(Exponential Backoff) 시뮬레이션 | ||
| 기본값(5회) 기준으로 재시도 시 대기 시간은 다음과 같이 늘어납니다. | ||
|
|
||
| | 시도 차수 | 계산식 (초) | 대기 시간 | 누적 대기 시간 | | ||
| | :--- | :--- | :--- | :--- | | ||
| | 1차 재시도 | `1 * 2^0` | 1초 | 1초 | | ||
| | 2차 재시도 | `1 * 2^1` | 2초 | 3초 | | ||
| | 3차 재시도 | `1 * 2^2` | 4초 | 7초 | | ||
| | 4차 재시도 | `1 * 2^3` | 8초 | 15초 | | ||
| | 5차 재시도 | `1 * 2^4` | 16초 | 31초 | | ||
| | **Total** | - | - | **약 31초 + API 수행 시간** | | ||
|
|
||
| #### 자동 재시도 대상 에러 | ||
| SDK는 다음 HTTP 상태 코드에 대해 자동으로 재시도를 수행합니다. | ||
| - **500 (Internal Server Error)**: 서버 내부 오류. | ||
| - **502 (Bad Gateway)**: 게이트웨이 오류. | ||
| - **503 (Service Unavailable)**: 서비스 일시 중단. | ||
| - **504 (Gateway Timeout)**: 게이트웨이 타임아웃. | ||
| > **Note**: **429 (Too Many Requests)** 에러는 SDK 레벨의 재시도에서 **제외**되었습니다 (Fail-Fast 적용). 이는 애플리케이션 레벨에서 즉각적으로 감지하고 대응(Rate Limit 롤백 취소 등)하기 위함입니다. | ||
|
|
||
| #### Jitter (불규칙성) | ||
| Thundering Herd(동시다발적 재시도로 인한 2차 폭주)를 방지하기 위해, 대기 시간에 무작위 값(Jitter)이 추가되어 기본적으로 분산됩니다. | ||
|
|
||
| ### 4.3 재시도와 토큰 사용량 추적의 트레이드오프 (Trade-off Analysis) | ||
|
|
||
| 우리 시스템은 `GeminiTokenTracker`를 통해 토큰 사용량을 기록하고 나중에 가용 `Client`를 선택하는 데 활용합니다. 하지만 **SDK 내부 재시도**가 발생할 경우, 재시도 과정에서 소모된 토큰은 최종 성공 응답에만 포함되거나, 실패 시 누락될 수 있다는 잠재적 오차가 존재합니다. | ||
|
|
||
| #### 이슈 정의 (The Discrepancy) | ||
| - **상황**: 1차 시도 (500 에러) -> 2차 시도 (성공) | ||
| - **현상**: 애플리케이션은 **2차 시도의 성공 토큰**만 기록합니다. 1차 시도에서 토큰이 소모되었더라도 기록되지 않습니다. | ||
|
|
||
| #### 트레이드오프 분석 (Why it's acceptable) | ||
| 이러한 오차를 감수하고 SDK 재시도를 사용하는 이유는 다음과 같습니다. | ||
|
|
||
| 1. **과금 정책 (Billing)**: 일반적으로 Google Cloud를 포함한 대다수의 클라우드 API는 `5xx` (Internal Server Error) 발생 시 **과금하지 않습니다**. 따라서 1차 시도(500 에러)가 누락되더라도 실제 비용이나 한도(Quota)에는 영향이 거의 없습니다. | ||
| 2. **안정성 우선 (Stability > Accounting)**: 정확한 토큰 카운팅보다 중요한 것은 사용자의 요청을 **성공시키는 것**입니다. 재시도를 통해 일시적 오류를 극복하는 것이 UX 관점에서 훨씬 중요합니다. | ||
| 3. **429 에러 제외**: 유일하게 과금이나 Quota에 민감할 수 있는 `429 (Rate Limit)` 에러는 SDK 재시도에서 **제외**했습니다. 따라서 Rate Limit 관련 에러는 즉시 감지되고 애플리케이션 로직에 의해 정확히 처리됩니다. | ||
| 4. **408 (Request Timeout) 제외**: 무료 티어(Free Tier) 사용 시 RPM/RPD(일일/분당 요청 수) 제한이 엄격합니다. 408 에러가 SDK 내부에서 재시도될 경우, 우리 시스템이 집계하지 못한 '숨겨진 요청'이 발생하여 Quota 관리의 정확도가 떨어질 수 있습니다. 따라서 **Accurate Accounting(정확한 집계) > UX/Stability** 원칙에 따라 408도 재시도에서 제외합니다. | ||
|
|
||
| **결론**: `5xx` (서버 오류)만 제한적으로 재시도하며, 클라이언트 측 이슈나 과금/Quota에 영향을 줄 수 있는 `429`, `408`은 즉시 실패 처리(Fail-Fast)하여 시스템의 예측 가능성을 확보했습니다. | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
문서의 재시도 설정 구조 표에서
exp_base라는 파라미터를 사용하고 있으나, 실제 적용된 Java SDK에서는multiplier를 사용합니다. 문서와 코드의 일관성을 위해multiplier로 수정하는 것이 좋겠습니다.