배경 및 목표
AI 서류 평가를 요청할 수 있는 경로가 여러 엔드포인트에 분산되어 있었습니다. 어떤 경로에서든 요청이 들어오면 누락 없이 100% 평가를 요청하고 결과를 보장해야 했고, 외부 AI 서비스의 장애 상황에서도 결과가 유실되면 안 되었습니다.
목표
- 분산된 여러 트리거를 누락 없이 하나의 평가 요청으로 수렴시킨다.
- 외부 AI 장애·콜백 유실 상황에서도 평가 결과를 100% 보장한다.
해결 방법과 해결 후보군
1. 이미 발행 중인 내부 이벤트를 활용
각 엔드포인트는 이미 자체적인 내부 이벤트(ApplicationEvent)를 발행하고 있었습니다. AI 서류 평가를 위해 별도 트리거를 새로 만드는 대신, 기존에 발행되고 있던 이벤트들을 구독하는 방식으로 설계했습니다. 이를 통해 기존 코드를 수정하지 않고도 AI 평가 요청을 통합할 수 있었고, 앞으로 새로운 트리거가 추가되더라도 해당 이벤트만 구독하면 됩니다.
@TransactionalEventListener의 AFTER_COMMIT phase를 적용하여, 트랜잭션이 커밋된 후에만 이벤트 핸들러가 동작하도록 했습니다. 트랜잭션 롤백 시 불필요한 AI 평가 요청이 발생하지 않도록 안정성을 확보했습니다.
2. 콜백 Endpoint로 결과 수신
외부 AI 서비스는 평가에 수 분이 소요되므로 동기 호출이 불가능합니다. Kafka로 요청을 전달하고, 외부 AI 서비스가 완료 후 콜백 Endpoint로 결과를 전달하는 구조를 설계했습니다. 콜백 수신 시 평가 결과를 저장하고, 채용담당자가 조회할 때 즉시 서빙합니다.
3. 재처리 배치로 장애 대비
정상 플로우만으로는 “100% 완료”를 보장할 수 없습니다. 콜백이 네트워크 순단 등으로 실패하면 결과가 영구 유실될 수 있기 때문입니다. 이를 방지하기 위해 다음과 같은 재처리 배치를 설계했습니다.
- 특정 시간마다 배치 트리거: 스케줄러가 주기적으로 배치를 실행합니다.
- “요청” 상태의 서류 평가 조회: 요청 후 일정 시간이 지났는데 아직 “요청” 상태로 남아있는 건을 조회합니다.
- 비즈니스 로직으로 지연 건인지 판단: 요청 시간, 상태 등을 기준으로 정상 대기인지 지연인지 판단합니다.
- 외부 서버에 상태 확인: 지연 건으로 판단되면 외부 서버에 실제 상태를 확인합니다. 실제 지연(처리 중)인지, 장애로 콜백이 누락된 것인지를 구분하여, 누락 건은 콜백을 다시 받고 지연 건은 재요청합니다.
- 재시도는 최대 3회: 3회 초과 시 Slack 알림으로 운영팀이 수동 대응할 수 있도록 했습니다.
전체 처리 흐름
sequenceDiagram participant C as 채용담당자 participant API as API participant Event as 기존 이벤트 participant Handler as 이벤트 핸들러 participant Kafka as Kafka participant AI as 외부 서비스 participant CB as 콜백 Endpoint participant Batch as 재처리 배치 C->>API: 평가 요청 트리거 API->>Event: 기존 내부 이벤트 발행 API-->>C: 즉시 응답 ("평가 요청 중") Note over Event,Handler: AFTER_COMMIT 후 실행 Event->>Handler: 이벤트 구독 Handler->>Kafka: 메시지 발행 Kafka->>AI: 평가 요청 AI->>AI: 처리 (수 분) AI->>CB: 결과 콜백 CB->>API: 결과 저장 + 서빙 Note over Batch: 주기적 실행 Batch->>Batch: "지연" 상태 건 감지 Batch->>AI: 재요청
결과
| 지표 | 결과 |
|---|---|
| 평가 요청 누락 | 0건 |
| 클라이언트 응답 | 40~50ms (즉시) |
| 벌크 200건 | 80ms |
기존 코드를 수정하지 않고 이벤트 구독만으로 AI 평가를 통합했으며, 3겹 안전장치로 정상 플로우뿐 아니라 장애 상황에서도 결과를 보장합니다.
모니터링
- ‘요청’ 상태로 장시간 남은 평가 건수(지연/누락 감지)를 관측한다.
- 재처리 배치 재시도 횟수와 3회 초과 시 Slack 알림을 운영한다.