Skip to content

fix(backend): 헬스체크에서 RabbitMQ 상태가 항상 UNKNOWN 이던 문제 - #183

Merged
i3months merged 1 commit into
devfrom
fix/rabbitmq-health-path
Aug 19, 2026
Merged

fix(backend): 헬스체크에서 RabbitMQ 상태가 항상 UNKNOWN 이던 문제#183
i3months merged 1 commit into
devfrom
fix/rabbitmq-health-path

Conversation

@i3months

Copy link
Copy Markdown
Member

어떻게 찾았나

배포된 dev(https://stack-up.shop)의 /api/system/health 를 실제로 찔러 봤다.

{
  "status": "UNKNOWN",
  "components": {
    "database": { "status": "UP", "details": { "database": "PostgreSQL", ... } },
    "rabbitmq": { "status": "UNKNOWN", "details": {} },
    "s3":       { "status": "UNKNOWN", "details": {} },
    "aiServer": { "status": "UNKNOWN", "details": {} }
  }
}

database 만 UP 이고 rabbitmq 는 details 까지 비어 있었다.

원인

SystemHealthService 는 Actuator 컴포넌트를 이름으로 조회한다:

private static final ComponentSpec DATABASE = new ComponentSpec("database", "db");
private static final ComponentSpec RABBITMQ = new ComponentSpec("rabbitmq", "rabbitmq");  // ← 없는 키

Spring 은 rabbitHealthContributor 빈을 등록하므로 Actuator 키는 rabbit 이다(빈 이름에서 접미사를 뗀 값). RabbitHealthContributorAutoConfiguration 소스로 확인했다.

없는 이름이라 healthEndpoint.healthForPath("rabbitmq") 가 null 을 돌려주고 그대로 UNKNOWN 이 된다 — 예외가 아니라 조용한 무응답이라 눈에 띄지 않았다.

바로 옆의 database"db" 로 올바르게 매핑돼 있다. 응답 키와 Actuator 키를 분리한 ComponentSpec(name, actuatorPath) 구조 자체는 맞았고, rabbit 값만 틀렸다. 공개 응답 키는 rabbitmq 그대로 유지된다.

영향

/api/system/ready 는 database·rabbitmq 를 종합하는데, rabbitmq 가 영구 UNKNOWN 이라 readiness 가 항상 UNKNOWN 이었다. readiness 판단에 쓸 수 없는 상태다.

RabbitMQ 가 죽으면 질문 생성·꼬리질문·피드백·음성 분석이 전부 멎는다. 제품이 사실상 죽는데 이 엔드포인트는 아무것도 알려주지 않았다.

컨테이너 healthcheck 는 Spring 자체 /actuator/health(Actuator 종합)를 쓰므로 배포 게이트 자체는 영향이 없었다 — RabbitMQ 장애 시 배포는 정상적으로 실패한다. 문제는 운영 중 모니터링용 공개 API 쪽이다.

테스트가 왜 못 잡았나

픽스처를 "rabbitmq" 키로 레지스트리에 등록해서 같은 실수를 그대로 재현하고 있었다. 프로덕션에서 Spring 이 "rabbit" 으로 등록한다는 사실이 테스트에 반영된 적이 없다.

  • 기존 두 테스트의 픽스처를 실제 Actuator 키(rabbit)로 교정
  • health_readsRabbitFromActuatorKeyNotResponseKey — 응답 키는 rabbitmq 로 유지하면서 Actuator 는 rabbit 에서 읽는지, details 까지 전달되는지
  • health_reportsUnknownWhenActuatorHasNoSuchComponent — 없는 이름일 때의 동작을 분리해 고정

남는 것 (이 PR 범위 밖)

s3 · aiServer 는 커스텀 indicator 가 아직 없어 UNKNOWN 이고, 그래서 /health종합 status 는 여전히 UNKNOWN 으로 고정된다(기존 테스트가 이 상태를 의도로 명시하고 있다). 이 PR 로 /ready(database·rabbitmq)는 정상 동작하게 된다.

두 indicator 를 실제로 구현하려면 S3 headBucket, AI 서버 GET /health 호출이 필요하다 — 별도 작업으로 두는 게 맞다고 봤다. docs/observability.md 에 현재 상태를 적어뒀다.

영향 범위

  • DB 마이그레이션: 없음
  • API contract 변경: 없음 (응답 키 rabbitmq 유지, 값만 실제 상태로)
  • 환경변수: 없음

리뷰어 체크포인트

  • /health 종합 status 를 쓸 수 있게 하려면 s3·aiServer indicator 구현이 필요하다. 우선순위 판단 부탁

배포된 dev 의 `/api/system/health` 를 실제로 찔러 보다 발견했다. database 만 UP 이고
rabbitmq 는 details 까지 빈 채 UNKNOWN 이었다.

`SystemHealthService` 는 Actuator 컴포넌트를 이름으로 조회하는데, RabbitMQ 를 `"rabbitmq"`
로 찾고 있었다. Spring 은 `rabbitHealthContributor` 빈을 등록하므로 실제 키는 **`rabbit`**
이다(빈 이름에서 접미사를 뗀 값). 없는 이름이라 `healthForPath` 가 null 을 돌려주고
그대로 UNKNOWN 이 된다 — 예외가 아니라 조용한 무응답이라 눈에 띄지 않았다.

바로 옆의 `database` 는 `"db"` 로 올바르게 매핑돼 있었다. 응답 키와 Actuator 키를 분리한
`ComponentSpec(name, actuatorPath)` 구조는 이미 맞았고, rabbit 값만 틀렸다.

영향: `/api/system/ready`(database·rabbitmq 종합)가 **항상 UNKNOWN** 이라 readiness 판단에
쓸 수 없었다. RabbitMQ 가 죽으면 질문 생성·피드백·음성 분석이 전부 멎는데 이 엔드포인트는
아무것도 알려주지 않는다. (컨테이너 healthcheck 는 Spring 자체 `/actuator/health` 를 쓰므로
배포 게이트 자체는 영향 없었다.)

## 테스트가 왜 못 잡았나

픽스처를 `"rabbitmq"` 키로 등록해서 **같은 실수를 그대로 재현**하고 있었다. 실제 Actuator
키로 바꾸고, 매핑 자체를 못 박는 테스트 2개를 추가했다 — 응답 키는 rabbitmq 로 유지하면서
Actuator 는 rabbit 에서 읽는지, 그리고 없는 이름일 때 UNKNOWN 이 되는지.

`docs/observability.md` 에 키가 다르다는 점과 s3·aiServer 미구현으로 `/health` 종합 status 가
UNKNOWN 으로 고정된다는 점을 적었다.
@i3months
i3months merged commit 3627e04 into dev Aug 19, 2026
5 checks passed
@i3months
i3months deleted the fix/rabbitmq-health-path branch August 19, 2026 06:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant