[Django] Redis, Celery 조합으로 비동기 작업



DJANGO X REDIS X CELERY



연관된 글(딩그르르 포스트)
아래글은 이 포스트를 잘 이해하는데 도움이 됩니다.



1. Celery 

MVC패턴인 Django는 정보를 클라이언트로 전달하기 위해 View에서 무엇을 작업할지 확인하고 거기서 나오는 정보를 클라이언트로 전달합니다. 그렇기 때문에, View에서 작업하는 모든 작업이 끝나지 않으면 렌더링을 시작하지 않습니다. 그럼 사용자는 페이지가 넘어가는 화면을 계속 지켜만 보고 있어야하죠. 이 시간이 1초만 되도 사용자들은 느리다고 생각할 것입니다. 그래서 열심히 캐시도 하고~ 쿼리 튜닝도 하고~ 많은 것들을 진행합니다.


근데 긴 작업을 수행해야 한다면(예를 들어 다른 외부 API를 접속해서 정보를 가지고 와야 한다거나..), 그리고 그것이 리턴값이 필요하든, 리턴을 할 필요없는 기능이든 비동기 작업으로 빼야 합니다. 사용자 경험을 보다 우아하고 엘레강스하게 만들기 위해서요.


Celery를 굳이 쓰지 않더라도 어떤 방법으로든 비동기 작업으로 만들어야 합니다.

Celery 공식문서


아래는 대략적인  워크플로우 입니다.




2. Celery 설치 및 Django 세팅

우선 가상환경을 활성화 시켜줍니다. 우리는 6가지 작업을 할 것 입니다.

  1. 디펜던시 설치
  2. settings.py 에 변수 추가
  3. celery.py 생성
  4. __init__.py 수정
  5. tasks.py 생성
  6. DB Migrations

보통 일이.. 아니지요? ㅎㅎ



디펜던시 설치

Pycharm을 이용하시면 이미 활성화 되어 있으실거니 Ctrl + Alt + S 를 눌러 디펜던시를 설치 해 주셔도 됩니다.

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



프로젝트 settings.py 수정
INSTALLED_APPS = [
...
'django_celery_beat',
'django_celery_results',     ...
]
CELERY_ALWAYS_EAGER = True
CELERY_BROKER_URL = 'redis://127.0.0.1:6379'
CELERY_RESULT_BACKEND = 'redis://127.0.0.1:6379'
CELERY_ACCEPT_CONTENT = ['application/json']
CELERY_TASK_SERIALIZER = 'json'
CELERY_RESULT_SERIALIZER = 'json'
CELERY_TIMEZONE = 'Asia/Seoul'

위 두 부분을 추가해 줍니다. 수정하고 할 것도 없습니다. 이해는 나중에하고 먼저 돌려봐요.



celery.py 생성
from __future__ import absolute_import
import os
from celery import Celery


os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'proj.settings')
app = Celery('proj')

# 문자열로 등록은 Celery Worker가 자식 프로세스에게 피클링하지 하지 않아도 되다고 알림
# namespace = 'CELERY'는 Celery관련 세팅 파일에서 변수 Prefix가 CELERY_ 라고 알림
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폴더가 아닌 프로젝트 폴더. settings.py 가 있는 폴더 안에 만드세요!



__init__.py 수정
from __future__ import absolute_import
from .celery import app as celery_app


**주의

프로젝트 안에 __init__.py가 많지만, project 폴더 안에 있는 __init__.py 입니다. 이 폴더 안에 당신의 settings.py, urls.py, wsgi.py 등이 있습니다.



tasks.py 생성
from __future__ import absolute_import, unicode_literals
from celery import shared_task
from app.components.celery_tasks import visitors

@shared_task
def add(x + y):
return x + y


@shared_task
def ga_collect():
visitors()


**주의

ga_collection()은 제가 쓰는 Celery 작업입니다. 같이 넣으시면 오류나요!
그리고 app폴더 안에 생생합니다.




DB Migrations
$ python manage.py makemigrations
$ python manage.py migrate




다시 settings.py에 추가
SCHEDULE_MINUTE = 60
SCHEDULE_HOUR = 60 * SCHEDULE_MINUTE
SCHEDULE_DAY = 24 * SCHEDULE_HOUR
SCHEDULE_WEEK = 7 * SCHEDULE_DAY
SCHEDULE_MONTH = 30 * SCHEDULE_DAY

CELERY_BEAT_SCHEDULE = {
'ga_collect': {
'task': 'app.tasks.ga_collect',
'schedule': 5 * SCHEDULE_MINUTE,
# 'schedule': 2.0,
# 'args': (4, 4)
}
}

이건 settings.py 파일에 하드코딩으로 박아넣는 겁니다. Django-Celery-Beat을 사용하면 인터벌 등을 DB로 동적관리 할 수 있습니다.

그리고 시간을 표현하는 방법은 timedelta를 쓰는 방법, 저처럼 쓰는 방법 crontab을 쓰는 방법 등 이 있는데, 저는 리눅스(Ubuntu 18.04)와 윈도우를 왔다 갔다 하면서 개발을 지속합니다. Crontab은 윈도우에서 실행이 안되기 때문에, 개발할때 가급적이면 그 어떤 프로젝트에도 Crontab을 쓰지 않습니다. 특히 오픈소스 일 경우 윈도우 유저는 사용이 안되거든요. 

Celery는 좀 예외일 수 있는게... 어짜피 윈도우에서 Celery가 잘 안돌아 갑니다. 지원을 중단했습니다. ㅋㅋㅋ




3. Celery 실행

Django를 다시 시작하고(중요함)

윈도우시라면 윈도우키 + R,  cmd 라고 입력하셔서 커맨드 창을 여세요.  다른 OS도 전부 콘솔창을 열어 줍니다.(2개 열어 줍니다, 그리고 한창에 하나씩 써보세요. 순서대로. 잘 돌아가는 것을 확인하실 수 있습니다.)

$ celery -A proj worker -l info
$ celery -A proj beat -l info




4. 다음편에서 다룰 것들

  • 리눅스에서 Celery를 Demonize 하여 실행하기 > 바로이동


  • [[a.original_name]] ([[a.file_size | fileSizer]])
'Django에서 Redis 사용하기' 시리즈 포스트
[Django] Redis, Celery 조합으로 비동기 작업
2020-03-25
[Redis] 도커(Docker)로 Redis 설치하기
2020-03-23
좋아요[[ postLike | likePlus ]]
공유
라이언

“Lead Python Engineer”

댓글 [[totalCommentCount]]
[[ comment.author__nick_name ]] [[ comment.datetime_updated | formatDate]] (수정됨)

[블라인드 처리된 글 입니다.]

답장
[[ sub.author__nick_name ]] [[ sub.datetime_created | formatDate ]] (수정됨)

취소
댓글을 남겨주세요.
'Django' 관련 최신 포스트
[[ post.title ]]
[[ post.datetime_published_from | DateOnly ]]