Python 비동기 작업 큐 구현 - Celery와 Redis 조합
문제 상황
사용자가 프로필 이미지를 업로드하면 3가지 사이즈(썸네일, 중간, 원본)로 리사이징하는 API가 있었다. 동기 처리 방식이라 응답 시간이 평균 4~5초가 걸렸고, 이미지 크기가 클 경우 타임아웃이 발생했다.
Celery 도입
Celery는 Python의 분산 작업 큐 라이브러리다. Redis를 메시지 브로커로 사용했다.
# celery_app.py
from celery import Celery
app = Celery('tasks', broker='redis://localhost:6379/0')
@app.task
def resize_images(image_path, user_id):
from PIL import Image
sizes = [(150, 150), (500, 500), (1920, 1920)]
for size in sizes:
img = Image.open(image_path)
img.thumbnail(size)
img.save(f"{user_id}_{size[0]}.jpg")
API에서는 작업을 큐에 넣고 즉시 응답한다.
# api.py
@app.route('/upload', methods=['POST'])
def upload_image():
file = request.files['image']
path = save_temp_file(file)
# 비동기 작업 등록
resize_images.delay(path, current_user.id)
return {"status": "processing"}, 202
결과
API 응답 시간이 평균 400ms로 단축되었다. Worker 프로세스는 별도 서버에서 실행하며, 트래픽이 많을 때는 worker 수를 늘려 확장할 수 있다.
celery -A celery_app worker --loglevel=info --concurrency=4
작업 실패 시 재시도 로직과 모니터링은 Flower를 사용해 구성했다. 재택근무 전환 시점에서 인프라 안정성이 중요해졌는데, 이 구조가 도움이 되었다.