Post

[둥지] Celery 작업 실패 시 복구 로직 설계

둥지 프로젝트의 Celery 작업 실패 복구 메커니즘을 정리합니다. ACK 지연, 재시도 정책, Heartbeat 기반 워커 모니터링, 시나리오별 복구 흐름을 다룹니다.

[둥지] Celery 작업 실패 시 복구 로직 설계

분산 비동기 환경에서는 워커 크래시, 네트워크 단절, 로직 예외 등 다양한 이유로 작업이 중간에 실패할 수 있습니다. 둥지의 OCR 워커는 Celery의 기본 메커니즘에 커스텀 Heartbeat와 알림을 더해 이런 상황에 대응합니다.


아키텍처 구성

항목내용
브로커Redis
결과 백엔드없음 (결과는 DB에 직접 저장)
ocr
워커 동시성concurrency=1

결과 백엔드를 두지 않는 대신, 태스크 완료 시 서비스 레이어에서 직접 DB 상태를 갱신합니다. 이 방식은 Celery 결과 저장소와 DB 사이의 정합성 문제를 제거합니다.


복구를 위한 네 가지 설정

1. ACK 지연 (task_acks_late=True)

ACK(Acknowledgment)는 브로커에게 “이 작업 받았다”고 보내는 확인 신호입니다. 브로커는 ACK를 받은 시점에 해당 작업을 큐에서 제거합니다.

1
2
3
4
5
6
7
브로커(Redis)             워커
    │                      │
    │── 작업 전달 ────▶    │
    │                      │ 작업 처리 중...
    │◀── ACK ──────────   │ (완료 후 확인 신호 전송)
    │                      │
    └─ ACK 받으면 큐에서 해당 작업 제거

기본 동작(task_acks_late=False)은 작업을 꺼낼 때 즉시 ACK를 보냅니다. 워커가 처리 중에 죽어도 브로커는 이미 완료로 간주해 작업이 유실됩니다. task_acks_late=True로 설정하면 처리가 끝날 때 ACK를 보내므로, 워커가 처리 중에 크래시하면 브로커가 ACK를 받지 못해 해당 작업을 다시 큐에 넣습니다.

2. 프리페치 제한 (worker_prefetch_multiplier=1)

워커가 한 번에 하나의 작업만 가져오도록 제한합니다. concurrency=1 환경에서 작업 간 간섭을 막고, 실패 시 정확히 해당 작업만 재시도할 수 있습니다.

3. 태스크 재시도

예외 발생 시 최대 2회까지 30초 간격으로 재시도합니다. 재시도 횟수를 모두 소진하면 DB 상태를 FAILED로 마감합니다. 이때 사용자에게는 SUCCESS 알림을 발송하는데, OCR 실패가 발급 성공 자체를 무효화하지 않도록 하기 위한 비즈니스 로직상 결정입니다.

4. Heartbeat

워커가 살아있는 동안 주기적으로 Redis에 키를 기록합니다. TTL을 주기의 3배로 설정해, 일정 시간 안에 갱신이 없으면 키가 만료되는 방식으로 워커 상태를 감지합니다. Celery의 worker_ready·worker_shutdown 시그널에 연결해 시작·종료 시점을 제어하며, 워커가 정상 종료할 때는 Discord 웹훅으로 알림을 발송합니다.


시나리오별 복구 흐름

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[워커 크래시]
  작업 처리 중 워커 프로세스 종료
    └─▶ ACK 미전송 → 브로커 타임아웃 후 작업 재큐
         └─▶ 재시작된 워커 또는 다른 워커가 재처리

[로직 예외 (재시도 가능)]
  태스크 실행 중 예외 발생
    └─▶ 재시도 횟수 확인
         ├─▶ 남아 있으면 → 30초 후 재시도 (최대 2회)
         └─▶ 소진 시 → DB FAILED 마감 + 사용자에게 SUCCESS 알림 발송

[워커 비정상 종료]
  Heartbeat 스레드 중단
    └─▶ Redis 키 TTL 만료 → 워커 죽음 감지
         └─▶ 모니터링 시스템에서 이상 감지 가능

OCR 실패 시 왜 SUCCESS 알림을 보내는가

OCR은 발급된 PDF에서 텍스트를 추출하는 후처리 단계입니다. OCR이 실패해도 PDF 파일 자체는 이미 발급되어 S3에 저장된 상태입니다. 사용자 입장에서는 파일을 받은 것이고, OCR 결과가 없다면 자동 분석이 제한될 뿐 발급 자체가 실패한 것은 아닙니다. 따라서 OCR 최종 실패를 발급 실패로 전파하지 않고, 알림은 SUCCESS로 유지하면서 DB에만 FAILED 상태를 기록합니다.

This post is licensed under CC BY 4.0 by the author.