🔍 검색 키워드: celery worker 에러 해결, celery worker not processing tasks, kombu connection refused, celery django redis 에러, celery worker 작업 안됨, celery OperationalError 해결
증상: 태스크를 보냈는데 Worker가 반응이 없다
Celery 써본 사람이라면 한 번씩 겪어봤을 상황이다. .delay() 또는 .apply_async()로 태스크를 넣었는데 처리가 안 된다. 워커 로그를 보면 아예 조용하거나, 아래 같은 에러가 떠 있다.
kombu.exceptions.OperationalError: [Errno 111] Connection refused
또는 워커 프로세스는 살아 있는데 태스크 큐에 메시지가 쌓이기만 하고 소비가 안 된다. Celery + Django + Redis 조합에서 특히 자주 터진다.
원인 분류
Celery 워커가 태스크를 처리하지 못하는 원인은 크게 세 가지다.
1. 브로커(Redis/RabbitMQ)에 연결이 안 됨
가장 흔한 원인. Redis가 아예 안 떠 있거나, 포트나 URL이 틀렸다.
# Redis 실행 여부 확인
redis-cli ping
# PONG 이 나와야 정상
# 포트 확인
netstat -an | grep 6379
Django settings에서 CELERY_BROKER_URL 확인:
# settings.py
CELERY_BROKER_URL = 'redis://localhost:6379/0' # 로컬
# Docker 환경이면
CELERY_BROKER_URL = 'redis://redis:6379/0' # 서비스명 주의
Docker Compose 쓸 때 실수가 잦다. 컨테이너 안에서 localhost는 자기 자신을 가리키기 때문에, Redis 컨테이너 이름(서비스명)을 써야 한다.
2. Celery 5.6.x 버전 버그 — Redis Reconnection 후 멈춤
이건 좀 억울한 케이스다. Celery 5.5.0에서 Kombu reconnection 버그를 고쳤는데, 5.6.x에서 같은 문제가 다시 들어왔다. 증상은 이렇다.
- 워커가 처음엔 잘 돌다가 Redis 재연결(failover, 재시작) 이후 멈춤
- 태스크가 큐에 들어오는 건 보이는데 워커가 pick-up 안 함
- 워커 프로세스는 살아 있음 (CPU 거의 0%)
# 현재 celery 버전 확인
pip show celery | grep Version
pip show kombu | grep Version
5.6.x라면 다운그레이드하거나 패치 버전을 기다려야 한다.
pip install "celery==5.5.0" "kombu==5.4.0"
3. Worker Concurrency 부족 — 큐는 차는데 처리 속도가 안 따라감
에러는 없는데 태스크가 밀리는 경우다. 기본 concurrency는 CPU 코어 수인데, I/O bound 작업이 많으면 이걸 올려야 한다.
# 현재 워커 상태 확인
celery -A myproject inspect active
celery -A myproject inspect reserved
celery -A myproject inspect stats
# concurrency 늘려서 실행
celery -A myproject worker --concurrency=16 --loglevel=info
# 여러 워커 프로세스 (celery multi)
celery multi start 4 -A myproject -Q default,priority --concurrency=8
디버깅 순서: 이 순서대로 확인해라
Step 1. 브로커 연결 직접 확인
# Django shell에서
from celery_app import app # 또는 본인 celery app
app.connection().ensure_connection(max_retries=3)
에러 없이 통과하면 브로커 연결은 OK다.
Step 2. 간단한 태스크로 테스트
# tasks.py
from celery import shared_task
@shared_task
def debug_task():
print("task executed!")
return "ok"
# Django shell에서
from myapp.tasks import debug_task
result = debug_task.delay()
print(result.get(timeout=10)) # "ok" 나오면 정상
Step 3. 워커 로그 레벨 올려서 확인
celery -A myproject worker --loglevel=DEBUG
[DEBUG/MainProcess] Received task: 라인이 안 뜨면 태스크가 워커까지 도달 자체를 못 하는 것. Received task:는 뜨는데 처리가 안 되면 concurrency 문제이거나 태스크 내부에서 죽는 것.
Step 4. Flower로 실시간 모니터링
pip install flower
celery -A myproject flower --port=5555
http://localhost:5555에서 워커 상태, 태스크 큐, 처리 속도를 한눈에 볼 수 있다.
상황별 체크리스트
| 증상 | 체크 항목 | 해결 방법 |
| kombu connection refused | Redis 실행 여부 | redis-cli ping → Redis 시작 |
| Docker에서 Redis 연결 실패 | BROKER_URL 호스트명 | localhost → 서비스명 변경 |
| 워커 재시작 후 멈춤 | Celery 버전 | 5.5.0으로 다운그레이드 |
| 큐 적체, 에러 없음 | concurrency 설정 | --concurrency 값 증가 |
| 태스크 timeout | 작업 시간 초과 | soft_time_limit, time_limit 설정 |
| 특정 큐만 처리 안 됨 | 워커 큐 설정 | -Q 파라미터로 큐 명시 |
실무 설정 예시
Django settings.py — 권장 Celery 설정
# Celery 설정
CELERY_BROKER_URL = os.environ.get('CELERY_BROKER_URL', 'redis://localhost:6379/0')
CELERY_RESULT_BACKEND = os.environ.get('CELERY_RESULT_BACKEND', 'redis://localhost:6379/1')
# 작업 직렬화
CELERY_TASK_SERIALIZER = 'json'
CELERY_RESULT_SERIALIZER = 'json'
CELERY_ACCEPT_CONTENT = ['json']
# 타임존
CELERY_TIMEZONE = 'Asia/Seoul'
CELERY_ENABLE_UTC = True
# 재시도 설정
CELERY_TASK_ACKS_LATE = True # 처리 완료 후 ack
CELERY_WORKER_PREFETCH_MULTIPLIER = 1 # 한 번에 하나씩
# 태스크 타임아웃
CELERY_TASK_SOFT_TIME_LIMIT = 300 # 5분 경고
CELERY_TASK_TIME_LIMIT = 360 # 6분 강제 종료
Docker Compose 설정 예시
version: '3.8'
services:
redis:
image: redis:7-alpine
ports:
- "6379:6379"
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 3s
retries: 5
web:
build: .
depends_on:
redis:
condition: service_healthy
environment:
- CELERY_BROKER_URL=redis://redis:6379/0
celery_worker:
build: .
command: celery -A myproject worker --concurrency=4 --loglevel=info
depends_on:
redis:
condition: service_healthy
environment:
- CELERY_BROKER_URL=redis://redis:6379/0
Docker Compose에서 depends_on: condition: service_healthy를 안 쓰면, Redis가 완전히 뜨기 전에 Celery worker가 연결 시도해서 connection refused가 뜬다.
Celery Beat (스케줄러) 별도로 떠야 한다
가끔 보면 periodic task가 실행이 안 된다는 이슈가 있는데, celery beat를 별도 프로세스로 안 띄워서 그런 경우가 있다.
# beat는 반드시 별도로 실행
celery -A myproject beat --loglevel=info --scheduler django_celery_beat.schedulers:DatabaseScheduler
beat와 worker를 같은 프로세스로 돌리는(-B 옵션) 건 개발환경에서만 써라. 프로덕션에서는 반드시 분리해야 한다.
마무리
Celery 문제는 대부분 브로커 연결 문제 아니면 버전 버그다. 위 순서대로 하나씩 확인하면 대부분 잡힌다. Docker 환경에서는 서비스명 vs localhost 혼동이 제일 많으니 그것부터 봐라.
실무에서 직접 겪은 내용 기반으로 작성했습니다. 틀린 부분 있으면 댓글로 알려주세요.
댓글 없음:
댓글 쓰기