Skip to content

[BE] /gotchas 전 요청 500 — UN HANDLED EXCEPTION #507

Open

Description

@sumi-0011

증상

뽑기 API가 count 값과 무관하게 500을 반환합니다. 사용자에게는 "뽑기를 진행중입니다"가
약 10초 떠 있다가 "펫 뽑기에 실패했습니다" 토스트와 함께 모달이 닫히는 것으로 보입니다.
제보 2건이 올라와 있습니다 (#505 2026-08-31, #506 2026-09-01).

포인트는 차감되지 않습니다. 5회 호출 동안 1,501,517p 그대로였습니다.

발견 배경

  1. 깃허브에서 바로가기 및 1만 p 뽑기가 안돼요 #506 제보자가 10,000p 뽑기 3회 실패를 보고 → 프론트 코드를 먼저 의심하고 가챠
    플로우 전체를 읽었으나 1연차와 10연차가 같은 함수를 호출하는 것을 확인
  2. 유효한 accessToken으로 API를 직접 호출 → count=10 에서 500 재현
  3. count 를 바꿔가며 재현 → count=1 에서도 동일하게 500

측정

요청 응답 소요
POST /gotchas?count=10 Api-Version 3 500 {"message":"UN HANDLED EXCEPTION"} 10.24s
POST /gotchas?count=10 Api-Version 3 (재시도) 500 동일 10.17s
POST /gotchas?count=2 Api-Version 3 500 동일 10.16s
POST /gotchas?count=1 Api-Version 3 500 동일 10.27s
POST /gotchas?count=10 Api-Version 2 404 {"message":"NOT FOUND"} 0.17s
GET /users (같은 토큰) 200 정상 0.1s

재현 커맨드:

curl -X POST "https://api.gitanimals.org/gotchas?count=1" \
  -H "Authorization: Bearer <token>" \
  -H "Api-Version: 3" \
  -H "Content-Type: application/json" \
  -d '{"count":1}'

원인

서버 내부 예외라 클라이언트에서는 특정 못 했습니다. 네 번 모두 10.16~10.27초에 응답이
온 것으로 보아 내부 호출 하나가 10초 만에 타임아웃되고, 그 예외가 처리되지 않아
500으로 응답하는 것으로 보입니다. 같은 토큰으로 /users 는 정상이므로 인증 문제는 아닙니다.

해결 방향

10초 만에 타임아웃되는 다운스트림을 특정하는 것이 먼저입니다. 그와 별개로 예외를
UN HANDLED EXCEPTION 으로 응답하는 부분은 원인 구분이 가능한 에러 코드로 바꿔주시면
프론트에서 "잠시 후 다시 시도해주세요"와 "포인트가 부족합니다"를 구분해 안내할 수 있습니다.

사용자 영향

현재 뽑기 기능 전체가 동작하지 않습니다. 포인트는 차감되지 않으므로 사용자 손실은 없고,
제보자들에게 그 점을 먼저 안내하면 좋겠습니다.

Activity

  1. sumi-0011 commented on Sep 2, 2026

    @sumi-0011
    MemberAuthor

    #505 쪽에서 서버 지표를 확인했습니다. 원인 지점이 다운스트림이 아니라 Netx saga 결과 대기 구간으로 좁혀집니다.

    10.2초의 정체

    Netx 의 saga 결과 대기 기본 타임아웃입니다.

    • OrchestratorManager.kt:79 — TEN_SECONDS_TO_TIME_OUT = 10000L
    • Orchestrator.kt:78 — 기본 timeoutMillis 10초, 미수신 시 ResultTimeoutException
    • GotchaFacadeV3.kt:36 — 타임아웃 인자 없는 sagaSync(...) 호출이라 기본값 적용

    다운스트림은 정상입니다

    api.gitanimals.org/actuator/prometheus 기준, 현재 프로세스 기동(2026-08-28 10:08 KST) 이후 5.0일 누적입니다.

    엔드포인트 200 건수 / 평균 500 건수 / 평균
    POST /gotchas 159 / 1.168s 115 / 10.156s (실패율 42%)
    POST /shops/backgrounds 5 / 0.78s 26 / 10.15s (83.9%)
    POST /shops/drop/{persona-id} 124 / 0.58s 14 / 10.17s (10.1%)
    POST /auctions/products/{id} (구매) 53 / 0.67s 8 / 10.15s (13.1%)
    POST /auctions/products (등록) 133 / 0.44s 21 / 135.9s
    GET /users (saga 아님) 31,603 / 0.023s 0
    POST /internals/users/points/decreases 218 0
    • 다운스트림 호출은 5xx 0건입니다. 10초에 걸리는 다운스트림이 없습니다.
    • 뽑기만의 문제가 아닙니다. saga 를 쓰는 쓰기 API 전부가 10.15초에 실패합니다.
    • 경매 등록만 135.9초인 것은 RegisterProductFacade 가 sagaSync(100000, ...) 으로 타임아웃을 100초로 명시하기 때문입니다. 타임아웃 값이 곧 실패 시간이라는 것이 두 지점에서 확인됩니다.
    • 포인트 차감 218건 전부 성공입니다. 실패한 saga 는 차감 단계에 도달하지 못했습니다. 이 이슈의 잔액 실측(1,501,517p 유지)과 일치합니다.

    saga 결과가 안 오는 지점

    RedisStreamSagaListener.kt:34 가 StreamReceiver 를 필드에서 한 번만 만들고 receive() 마다 같은 인스턴스를 씁니다. AbstractSagaListener.kt:39-45 는 doAfterTerminate { subscribeStream() } 로 재구독하지만 receive() 가 같은 receiver 를 다시 호출합니다. 커넥션 장애로 receiver 가 terminal 상태가 되면 재구독해도 그대로입니다.

    확인은 두 가지면 됩니다.

    • XPENDING NETX_STREAM api, XINFO GROUPS NETX_STREAM 의 consumer idle 시간
    • 로그에 Redis stream group created key "NETX_STREAM" 반복 출력 여부. 반복되면 무한 재구독으로 확정됩니다.

    수정은 Netx 에서만 가능합니다

    devxb/Netx#157(재구독 시 StreamReceiver 새로 생성)이 2026-08-28 merge 없이 close 되었고, RedisStreamSagaListener.kt 현재 main 에 private val receiver 가 그대로 있습니다.

    gitanimals-api 에서는 우회가 안 됩니다. Maven Central 최신이 0.5.0 이고 이미 0.5.0 을 쓰고 있어 bump 할 버전이 없고, RedisStreamSagaListener 와 RedisSagaConfigurer 의 @Bean 이 전부 internal 이라 리스너를 교체할 수 없습니다.

    근본 — devxb/Netx#157 재오픈·merge → 신규 버전 릴리스 → netxVersion 상향
    완화 — saga 미소비 감지 후 프로세스 재기동. #501 이 2026-08-29 에 재기동으로 닫혔는데, 그 인스턴스에서 뽑기 500 이 다시 115건 발생했습니다.

    클라이언트 쪽

    이 이슈의 "에러 코드로 바꿔달라" 요청과 별개로, 프론트에서 먼저 할 수 있는 부분은 PR 두 건으로 올렸습니다.

    서버가 에러 코드를 주기 시작하면 #405 의 gachaError.ts 한 곳만 고치면 됩니다.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions