Gemini overloaded를 장애가 아니라 제품 경로 문제로 보기

@givemethatsewon· May 14, 2026· 4 min read

상황 설명 도식
상황 설명 도식

Gemini final generation이 503 UNAVAILABLE로 실패했을 때 단순 retry만 붙이면 쉬웠다. 하지만 Place2Page에서 더 중요한 질문은 "어떤 실패를 사용자 흐름 안에서 흡수하고, 어떤 실패를 운영자에게 드러낼 것인가"였다. 그래서 capacity 계열 오류만 좁게 분류하고, 한 번만 fallback provider로 넘기며, 성공해도 fallback metadata를 남기도록 했다.

요약

  • 문제: Gemini final HTML generation에서 503, UNAVAILABLE, overloaded 같은 일시적 장애가 사용자 생성 흐름을 끊었다.
  • 판단: 모든 실패를 fallback으로 덮지 않고, provider capacity 문제로 볼 수 있는 오류만 흡수했다.
  • 해결: fallback model로 한 번만 재시도하고, 결과 metadata에 primary/fallback provider와 이유를 남겼다.
  • 배운 점: AI provider 장애는 숨길 문제가 아니라, 어떤 실패를 제품 경로에서 흡수할지 정하는 reliability 설계 문제다.

상황

Place2Page의 final HTML generation은 Gemini를 사용한다. 장소 데이터를 가져오고, meta prompt를 만들고, 마지막 단계에서 Gemini가 완성된 HTML을 생성한다.

대부분의 경우에는 잘 동작한다. 하지만 생성형 AI provider를 제품 흐름에 넣으면 피할 수 없는 문제가 있다.

외부 모델이 가끔 바쁘다.

Google Gemini API 공식 troubleshooting 문서에서도 503 UNAVAILABLE은 서비스가 일시적으로 overloaded 상태이거나 down 상태일 수 있다고 설명한다. 즉, 우리 코드가 항상 잘못되어서 발생하는 오류는 아니다.

문제는 사용자 입장에서는 이유가 중요하지 않다는 점이다. 사용자는 "Gemini가 바쁘구나"가 아니라 "내 페이지 생성이 실패했다"고 느낀다.

문제

처음에는 모델 호출 실패를 그대로 에러로 보여줬다. 이 방식은 디버깅에는 솔직하지만 사용자 흐름에는 약했다.

특히 final HTML generation은 전체 생성 과정의 마지막에 가깝다. 앞 단계에서 장소 정보를 가져오고, 메타 프롬프트를 만들고, 어느 정도 시간이 지난 뒤 마지막 모델 호출에서 실패하면 사용자 경험이 나쁘다.

그렇다고 모든 에러를 fallback으로 덮을 수도 없다.

예를 들어 API key가 잘못됐거나, 요청 payload가 잘못됐거나, 모델이 지원하지 않는 형식으로 호출된 경우까지 fallback으로 넘기면 진짜 문제를 숨기게 된다. 나중에는 왜 fallback이 자주 발생하는지 알기 어려워진다.

그래서 기준이 필요했다.

처음 생각한 가설

모든 실패를 똑같이 보지 말고, 일시적 capacity 문제만 사용자 흐름 안에서 흡수하면 된다고 봤다.

구분은 대략 이렇게 잡았다.

  • 흡수할 수 있는 실패: 503, UNAVAILABLE, high demand, overloaded
  • 바로 드러내야 하는 실패: 잘못된 설정, 인증 오류, 잘못된 요청, 코드 버그

전자는 provider 상태에 가까운 문제다. 같은 요청을 잠시 뒤나 다른 모델로 보내면 성공할 수 있다. 후자는 우리 쪽에서 고쳐야 하는 문제다. fallback으로 덮으면 안 된다.

확인한 증거

이 문제도 로그 문장만 보고 감으로 처리한 것은 아니었다. repo에 남은 테스트가 기준을 잘 보여준다.

Gemini stream 호출 실패 테스트는 이런 에러를 흉내낸다.

503 UNAVAILABLE. {'error': {'message': 'high demand'}}

이 에러는 내부 validation 실패나 prompt parsing 실패가 아니라 provider capacity 쪽에 가깝다. 그래서 generation service에는 capacity failure로 볼 marker가 따로 들어갔다.

503
unavailable
high demand
overloaded
temporarily unavailable
try again later

fallback 테스트는 첫 호출에서 Gemini가 503 UNAVAILABLE: high demand로 실패하고, 두 번째 호출에서는 gpt-5.3-codex로 넘어가는지를 본다. 성공 결과에는 fallback metadata도 남긴다.

provider_fallback_applied == True
provider_fallback_reason == "gemini_provider_unavailable"
primary_final_model_provider == "gemini"
final_model_provider == "openai"
final_model_id == "gpt-5.3-codex"

반대로 모든 Gemini 에러를 fallback하지 않도록 하는 테스트도 있다. 이 구분이 없으면 인증 오류나 잘못된 요청까지 fallback으로 숨길 수 있기 때문이다.

커밋으로 보면 267b3fc fix(api): fallback from busy Gemini to OpenAI에서 generation_service.py, config, tests, model routing docs가 같이 바뀌었다. 단순 retry가 아니라 model routing과 운영 관찰 metadata까지 포함한 수정이었다.

해결한 방식

final HTML generation에서 Gemini capacity failure로 볼 수 있는 오류를 감지했다. 그리고 fallback model이 설정되어 있고, 필요한 API key가 존재하며, primary model과 같은 모델이 아니라면 한 번 fallback으로 재시도했다.

중요한 점은 "한 번"이었다.

fallback은 무한 재시도 장치가 아니다. 사용자 흐름을 살릴 수 있는 최소한의 안전망이다. 계속 실패하면 실패로 인정해야 한다. 그래야 오류율과 원인을 관찰할 수 있다.

또 fallback이 발생했는지 metadata에 남겼다. 생성이 성공했다고 해서 모든 것이 정상인 것은 아니다. fallback으로 성공한 결과는 운영자가 나중에 볼 수 있어야 한다.

왜 단순 retry가 아니었나

일시적 장애라면 같은 모델에 retry를 걸 수도 있다. 실제로 짧은 retry는 의미가 있다.

하지만 AI 생성 제품에서는 latency도 중요하다. 사용자는 이미 페이지가 만들어지길 기다리고 있다. 같은 overloaded 모델에 여러 번 retry를 걸면 대기 시간이 늘어난다. 그래서 한 번의 제한적 retry 후 다른 provider/runtime으로 넘어가는 방식이 더 제품 흐름에 맞았다.

이때도 fallback model의 성격을 알아야 한다. 결과 품질이나 스타일이 primary model과 완전히 같지는 않을 수 있다. 그래서 fallback은 "아무거나 만들어서 성공 처리"가 아니라 실패보다 나은 대체 경로로 봐야 한다.

배운 점

AI provider 장애는 특별한 일이 아니라 운영 조건이다.

모델 API를 호출하는 제품은 언젠가 rate limit, overloaded, temporary unavailable을 만난다. 이때 중요한 것은 실패를 없애는 것이 아니라, 실패를 분류하는 것이다.

  • 사용자 흐름에서 흡수할 실패인가?
  • 운영자에게 드러내야 할 실패인가?
  • 바로 수정해야 할 설정 문제인가?
  • 재시도하면 나아질 수 있는 외부 상태인가?

이 구분 없이 fallback을 붙이면 장애를 숨긴다. 반대로 fallback이 전혀 없으면 외부 provider의 짧은 흔들림이 그대로 사용자 실패가 된다.

다음에는 이렇게 판단한다

비슷한 provider 장애를 다시 보면 fallback부터 붙이지 않는다. 먼저 실패가 일시적 capacity 문제인지, 잘못된 요청/인증/코드 문제인지 분리한다. 전자는 사용자 흐름 안에서 흡수할 수 있지만, 후자는 빨리 드러나야 한다.

앞으로 provider fallback을 다룰 때는 세 가지를 같이 본다.

첫째, fallback rate를 지표로 본다. fallback이 너무 자주 발생하면 primary provider 선택이나 quota, model routing을 다시 봐야 한다.

둘째, fallback 결과 품질을 별도로 본다. 성공 여부만 보지 않고, primary와 fallback의 output 품질 차이를 확인해야 한다.

셋째, 사용자에게 보여줄 메시지를 구분한다. 일시적으로 다른 경로를 사용했는지 굳이 모두 설명할 필요는 없지만, 완전히 실패했을 때는 재시도 가능한 문제인지 명확히 알려야 한다.

AI 제품에서 안정성은 모델 하나를 믿는 데서 나오지 않는다. 실패했을 때 어떤 길로 빠질지 미리 정해두는 데서 나온다.

참고

givemethatsewon profile
@givemethatsewon
프로젝트를 만들고 운영하면서 배운 개발, 제품, 디버깅 기록을 남깁니다.