DRF로 api 서버 개발(6) - celery

Dongwon Ahn·2020년 7월 28일
4

DRF로 API Server 개발

목록 보기
7/8
post-thumbnail

전 포스트에서는 장고에서 email 전송을 간단하게 하는 법에 대해 작성했습니다.
마지막에 작성한 것 처럼 간단하게 작성된 부분이라 api의 response time이 5초 정도 걸린다는 엄청난 문제점을 가지고 있습니다.
그렇기에 이번 포스트에서는 redis와 celery를 활용하여 이런 문제점을 해결해보겠습니다.

Celery란?

이메일 등과 같이 응답시간이 오래 걸리는 기능을 동기로 처리하는 것은 서비스의 엄청난 결격 사유가 될 수 있습니다. 오래 걸리는 작업을 비동기로 작업할 수 있게 해주는 파이썬 프레임워크입니다.

Redis-server

redis에 대한 설명은 이번 포스트에서 중요한 내용이 아니기 때문에 이번 포스트에서는 설명하지 않겠습니다.

레디스의 특징 중 redis-server를 쓸 수 있는 점이 있습니다. 이번 포스트에서는 그 server를 활용하려고 합니다.

Redis 설치 및 확인

저는 mac에서 작업을 했기 때문에 mac 기준으로 작성하겠습니다.
(추후 시간이 되면 window 버전도 추가하겠습니다...)

$ brew update
$ brew install redis
## redis start
$ brew services start redis

## redis stop
$ brew services stop redis

## redis background service (아래 이미지 처럼 나오면 됩니다.)
$ redis-server /usr/local/etc/redis.conf
## redis-server 확인 법
## pong 이 나오면 제대로 된 것입니다.
$ redis-cli ping

Celery 설치 및 설정

celery 설치 (가상환경을 세팅했으면 실수 하지말고 들어가셔서 설치해주세요.)

pip install celery
## 하는 김에 rediseh 설치하겠습니다.
pip install redis

메인 app 위치에 celery.py 파일을 생성합니다.

touch api_server/celery.py

아래 내용을 celery.py에 작성합니다.

## api_server/celery.py
from __future__ import absolute_import, unicode_literals
import os
from celery import Celery

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'api_server.settings')
app = Celery('api_server',backend='redis://', broker='redis://localhost:6379/0')
app.config_from_object('django.conf:settings', namespace='CELERY')
app.autodiscover_tasks()


@app.task(bind=True)
def debug_task(self):
    print("Request: {0!r}".format(self.request))
  • app = Celery('api_server',backend='redis://', broker='redis://localhost:6379/0')
    -> api_server 자리에는 메인 프로젝트 이름을 적어주시면 됩니다.

settings.py에 아래 내용을 추가합니다.

BROKER_URL = 'redis://localhost:6379/0'
CELERY_RESULT_BACKEND = 'redis://localhost:6379/0'
CELERY_ACCEPT_CONTENT = ['application/json']
CELERY_TASK_SERIALIZER = 'json'
CELERY_RESULT_SERIALIZER = 'json'
CELERY_TIMEZONE = TIME_ZONE

동일 디렉토리에 있는 __init__.py에 아래 내용을 작성합니다.

from __future__ import absolute_import
# This will make sure the app is always imported when
# Django starts so that shared_task will use this app.
from .celery import app as celery_app
__all__ = ('celery_app',)

이메일 코드 수정

celery 설정을 끝냈으니 이메일 전송을 celery 작업으로 할 수 있도록 코드를 수정하겠습니다.

task.py 생성
celery로 작업할 내용을 빼놓기 위해 testapi 디렉토리에 task.py 생성 후 아래 코드를 작성하겠습니다.

## testapi/task.py
from __future__ import absolute_import, unicode_literals
from celery import shared_task
from django.core.mail.message import EmailMessage
from api_server import settings
FROM_EMAIL = settings.EMAIL_HOST_USER

@shared_task
def send_email():
    subject = "이메일 테스트3"
    to = ['lemontech119@gmail.com']
    message = "email test가 성공했습니다."
    EmailMessage(subject=subject, body=message, to=to, from_email=FROM_EMAIL).send()
    return True
  • @shared_task : celery로 따로 작업할 코드라고 선언하는 부분입니다.

views.py 수정
이메일 전송을 task.py로 분리했기 때문에 views.py의 코드도 수정하겠습니다.

## testapi/views.py
from rest_framework.response import Response
from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import AllowAny
from .task import send_email

@api_view(['GET'])
@permission_classes([AllowAny])
def send_test_email(requset):
    send_email.delay()
    return Response({"message": "ok"})
  • send_email.delay() : 코드처럼 celery로 작업하고 싶은 작업은 delay()를 붙여줘야 합니다.

이메일 전송 Test (비동기)

  • Redis server를 가동합니다.
    • redis-server /usr/local/etc/redis.conf
  • Django 프로젝트 위치에서 터미널을 하나 더 켜서 celery worker를 작동시킵니다.
    • celery -A api_server worker -l info

      api_server 자리에는 메인프로젝트 name을 써주시면 됩니다.

  • Api Test

위의 사진처럼 response time이 1초 이내이며 메일이 전송이 되었다면 Test가 정상적으로 된 것입니다.


해당 시리즈에서 작업한 코드는 github에 업로드가 되어 있습니다.
부족한 점이나 잘못된 점이 있으면 댓글에 적어주시면 감사하겠습니다.

profile
Typescript를 통해 풀스택 개발을 진행하고 있습니다.

1개의 댓글

comment-user-thumbnail
2020년 12월 12일

안녕하세요, 덕분에 drf에 대해 많이 배우고 있습니다.

오타가 하나 있는데, 정정하시면 좋을 것 같아 남겨봅니다.

하는 김에 rediseh 설치하겠습니다.
->
하는 김에 redis도 설치하겠습니다.

답글 달기