Django에 Celery를 연결해보자

cloud_park·2023년 9월 19일
0

Celery?

어떻게 읽어야할지 무언가 생소한 이 단어는, '샐러리'라고 보통 읽는듯 하다.

Why Celery?

Django에서는 View의 처리가 완료되어야 Render가 시작된다. 하지만 Heavy한 작업이 필요한 경우 View에서 작업이 지연된다면, 사용자가 응답받을때까지 시간이 지연된다. 따라서 비동기적으로 작업을 처리할 수 있는 방법이 필요하다.

What's role of Celery?

이러한 비동기적인 작업을 처리하는 방식에서, 작업(Job)을 만드는 발행자(Publisher)작업자(Worker)의 역활이 생긴다.

Django에서 Celery를 통해 작업(Job)을 발행하면, 이 작업은 작업대메시지 큐에 쌓인다. 이 메시지 큐로는 RabbitMQ 혹은 Redis가 사용된다.

작업자작업대(메시지큐)의 메시지(작업)을 소비하고, 메시지큐에 작업이 완료되었다는 표식을 남긴다. 이러한 과정을 도와주는 역활이 샐러리이다. 그중 작업대 역활을 하는 메시지 큐브로커라고 불린다.

왜 이번 프로젝트에서 Celery를 사용?

이번 프로젝트는 API 콜을 하는데, API의 응답속도가 빠르지 않았다. 따라서 정보를 DB에 저장해주어야 할 필요가 있었다. 비동기적 작업을 하지 않을경우 이러한 작업이 사용자에게 응답이 만들어 지기전 이루어져, 사용자의 응답은 느려지게된다.

따라서 아래의 프로세스를 통해 사용자경험을 극대화하려한다. Celery를 사용하지 않으면 View가 종료되기 전 5번이 실행되어야하며, 이러한 과정에서 DB의 병목 및 응답시간 증가가 해소될 것으로 보인다.


1.사용자 요청
2.사용자 요청에 대해 API Call 이전 보유여부 확인
2-1) 사용자 요청에 맞는 정보가 Cache에 있는가?
2-2) 사용자 요청에 맞는 정보가 DB에 있는가?
3.Caching/DB에 없으면 API Call을 통해 정보를 갱신한다.
4.받아온 정보를 재가공하여 사용자에게 전달한다. (View 종료)
5. 데이터가공, DB 저장 및 Cache를 위한 Celery 테스크를 발행한다.


도움을 받은 글들
장고(Django)에서 셀러리(Celery) 사용하기 1편
Celery 공식 문서

Celery 설치하기

기존에는 Django와 결합된 별도의 패키지를 설치해야했지만, 이제는 Celery Stand-only로 설치가능하다.

pip install celery
pip install redis
pip install django-celery-beat
pip install django-celery-results 

django-celery-beat는 특정한 기간마다 작업이 실행하게하는 인터페이스,
django-celery-results는 작업결과를 알려줍니다. 

Celery 공식문서 - Django와 사용하기

Settings.py 설정

settings.py에서 아래 설정을 추가합니다.

INSTALLED_APPS = [
    ....
    'django_celery_beat',
    'django_celery_results',
    ...
]
 
 
# Celery
CELERY_ALWAYS_EAGER = True
CELERY_BROKER_URL = 'redis://localhost:6379'
CELERY_RESULT_BACKEND = 'redis://localhost:6379'
CELERY_ACCEPT_CONTENT = ['application/json']
CELERY_TAST_SERIALIZER = 'json'
CELERY_RESULT_SERIALIZER = 'json'
CELERY_TIMEZONE = 'Asia/Seoul'

celery.py 생성

Settings.py가 있는 프로젝트 (App이 아님!) 폴더에 생성해야합니다.

- proj/
  - manage.py
  - proj/ <이 폴더의 하위폴더!
    - __init__.py
    - settings.py
    - urls.py
import os

from celery import Celery

# Set the default Django settings module for the 'celery' program.
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'proj.settings')

app = Celery('proj')

# Using a string here means the worker doesn't have to serialize
# the configuration object to child processes.
# - namespace='CELERY' means all celery-related configuration keys
#   should have a `CELERY_` prefix.
app.config_from_object('django.conf:settings', namespace='CELERY')

# Load task modules from all registered Django apps.
app.autodiscover_tasks()


@app.task(bind=True, ignore_result=True)
def debug_task(self):
    print(f'Request: {self.request!r}')
 
proj/proj/__init__.py:
from .celery import app as celery_app

__all__ = ('celery_app',)

celery 구동 확인하기

celery -A proj worker -l INFO

manage.py가 있는 폴더에서 실행해야합니다. 그렇지 않는다면 Module 'proj' has no attribute 'celery' 같은 에러가 나옵니다.


잘 되었다면, python3 maange.py shell을 통해 날린 add 명령이 잘 동작해야합니다.

REDIS 확인하기

REDIS CLI를 통해 어떻게 명령이 들어갔는지 확인해봅시다. REDIS 설정하기를 통해 설정한 Docker Redis 기반입니다.

docker run -it --network redis-net --rm redis redis-cli -h django_redis
scan 0 
KEYS *을 사용하는 방법도 있지만, Redis는 Single-Thread 기반이여서, 재귀적으로 호출하는 scan0 를 사용하는것을 권장합니다. 

GET [내가 찾은 celery task 키]  

값이 잘 들어간 것을 확인할 수 있습니다.

ignore_result 사용하기

res = add.apply_async((1,2), ignore_result=True)
res.get()
res = add.apply_async((9,10))
res.get()

실제 실행결과는 아래와 같습니다.

Celery는 잘 실행을 했지만, 해당 결과값에 대해 저장을 하지 않으므로 값은 Redis에 남지 않습니다.

실제로 마지막에 실행한 0b89로 끝나는 Task만 Redis에 남아있습니다.

profile
Now in progress of untitled advance

0개의 댓글