04. 비동기 배치 celery 작업 처리

설치

celery 설치

$ pip install celery

RabbitMQ 서버 설치

$ sudo apt-get install rabbitmq-server

패키지를 설치하는 과정에서 우분투는rabbitmq 사용자와 rabbitmq 그룹을 추가한다.

RabbitMQ 서비스 시작 및 상태 확인

RabbitMQ 서비스를 아래와 같이 등록 구동한다.

$ sudo systemctl enable rabbitmq-server
$ sudo systemctl start rabbitmq-server

RabbitMQ 서비스의 구동 현황은 다음과 같이 확인할 수 있다.

systemctl status rabbitmq-server

Django 비동기 배치 작업 추가

guest 기본 사용자 제거 및 사용자 추가

RabbitMQ 서버 설치 시 디폴트 사용자 정보는 아래와 같다.

$ sudo rabbitmqctl list_users
Listing users ...
guest   [administrator]

현재 [administrator] 태그 표시가 되어 있는 guest 사용자 하나가 기본으로 생성되어 있으며 권한은 다음과 같이 확인할 수 있다.

$ sudo rabbitmqctl list_user_permissions guest
Listing permissions for user "guest" ...
/   .*  .*  .*

먼저 새로운 사용자를 egg 이름으로 추가한다. PASSWORD 대신에 적당한 비밀번호를 같이 적어줘야 한다.

$ sudo rabbitmqctl add_user egg PASSWORD
Creating user "egg" ...

새로 만들어진 egg 사용자는 어떤 태그도 없는데 여기에 administrator 태그를 설정해주도록 하고 결과를 확인한다.

$ sudo rabbitmqctl list_users
Listing users ...
guest   [administrator]
egg []
$ sudo rabbitmqctl set_user_tags egg administrator
Setting tags for user "egg" to [administrator] ...
$ sudo rabbitmqctl list_users
Listing users ...
guest   [administrator]
egg [administrator]

새 사용자 egg에게 모든 권한을 부여하고 권한 부여가 올바르게 되었는지 확인한다.

$ sudo rabbitmqctl set_permissions egg ".*" ".*" ".*"
Setting permissions for user "egg" in vhost "/" ...
$ sudo rabbitmqctl list_permissions
Listing permissions in vhost "/" ...
guest   .*  .*  .*
egg .*  .*  .*

이제 guest 사용자를 삭제한다.

$ sudo rabbitmqctl delete_user guest
Deleting user "guest" ...

conf/settings.py 파일 수정

앞서 egg 사용자를 만들었으고 PASSWORD 비밀번호로 RabbitMQ 서비스에 접속하기 위해 아래와 같이 CELERY_BROKER_URL 값을 다음과 같이 설정한다.

CELERY_BROKER_URL = 'amqp://egg:PASSWORD@localhost:5672//'

conf/celery.py 파일 추가

Celery 앱을 생성하기 위해 conf/celery.py 파일을 아래와 같이 작성할 수 있다.

from celery import Celery

app = Celery(conf)
app.config_from_object('django.conf:settings', namespace='CELERY')
app.autodiscover_tasks()

Celery 매뉴얼에서는 위 코드에서 os.environ.setdefault("DJANGO_SETTINGS_MODULE", "conf.settings.local") 같은 코드로 DJANGO_SETTINGS_MODULE 환경변수를 하드코딩으로 설정하게 되어 있는데 이 문서는 실행 시에 값을 넘겨주는 방법으로 설명한다.

conf/__init__.py 파일 수정

conf/__init__.py 파일을 수정하여 celery 모듈에서 app을 가져오는데 그 이름을 celery_app으로 한다.

from .celery import app as celery_app

__all__ = ['celery_app']

app/task.py 파일 추가

app/task.py 파일을 만들어서 비동기 배치 작업을 추가한다.

from celery import shared_task


@shared_task
def name_of_your_function(optional_param):
    print('작업 시간이 오래 걸리는 일')

이제 비로소 시간이 오래 걸리는 작업을 기술한다.

app/views.py 파일 등에서 비동기 작업 호출

뷰 파일 등에서 이제 비동기 작업을 호출해야 하는데 아래와 같이 호출할 수 있다.

from .tasks import name_of_your_function


name_of_your_function.delay(5)

작업자(worker) 프로세스 시작

$ DJANGO_SETTINGS_MODULE='conf.settings.local' celery -A conf worker -l info

위와 같이 작업자 프로세스를 시작시킬 수 있는데 conf 대신에 알맞는 프로젝트 이름을 지정해야 한다.

그리고 DJANGO_SETTINGS_MODULE 환경변수도 올바로 선언해야 한다. 이와 같이 하는 이유는 테스트환경과 개발환경에서 서로 다른 환경을 가지기 때문이다.

우분투 운영 서버에서 worker 프로세스 관리

/var/www/com.example.www/conf/celery.conf 파일을 아래와 같은 내용으로 새로 만든다.

# 노드, 워커 개수 (보통은 하나):
CELERYD_NODES="worker1"

# 'celery' 명령어의 절대 경로 위치:
CELERY_BIN="/var/www/com.example.www/venv/bin/celery"

# 앱 인스턴스 (예: Proj)
CELERY_APP="conf"

# manage.py 호출 방법
CELERYD_MULTI="multi"

# 워커로 전달할 추가 명령어 옵션
CELERYD_OPTS="--time-limit=300 --concurrency=8"

# - %n 노드 이름의 첫 부분
# - %I 현재 자식 프로세스 인덱스
#   prefork pool을 사용할 때 경쟁상태(race condition)을 피하기 위해 중요
CELERYD_PID_FILE="/var/www/com.example.www/run/celery-%n.pid"
CELERYD_LOG_FILE="/var/www/com.example.www/logs/celery-%n%I.log"
CELERYD_LOG_LEVEL="INFO"

/etc/systemd/system/celery.service 파일을 아래와 같은 내용으로 새로 만든다.

[Unit]
Description=Celery Worker
After=network.target

[Service]
Type=forking
User=egg
Group=developers
EnvironmentFile=/var/www/com.example.www/conf/celery.conf
WorkingDirectory=/var/www/com.example.www/repo
ExecStart=/bin/sh -c 'DJANGO_SETTINGS_MODULE=‘conf.settings.production' ${CELERY_BIN} multi start ${CELERYD_NODES} \
          -A ${CELERY_APP} --pidfile=${CELERYD_PID_FILE} \
          --logfile=${CELERYD_LOG_FILE} --loglevel=${CELERYD_LOG_LEVEL} ${CELERYD_OPTS}'
ExecStop=/bin/sh -c 'DJANGO_SETTINGS_MODULE=‘conf.settings.production' ${CELERY_BIN} multi stopwait ${CELERYD_NODES} \
       --pidfile=${CELERYD_PID_FILE}'
ExecReload=/bin/sh -c 'DJANGO_SETTINGS_MODULE=‘conf.settings.production' ${CELERY_BIN} multi restart ${CELERYD_NODES} \
          -A ${CELERY_APP} --pidfile=${CELERYD_PID_FILE} \
          --logfile=${CELERYD_LOG_FILE} --loglevel=${CELERYD_LOG_LEVEL} ${CELERYD_OPTS}'
StandardError=syslog

[Install]
WantedBy=multi-user.target

아래와 같이 위 스크립트를 등록 하는데 Celery 매뉴얼과 다른 중요한 차이점은 DJANGO_SETTINGS_MODULE=conf.settings.production과 같이 운영 환경에서 환경변수를 동적으로 정확히 지정해줘야 한다.

그리고 아래와 같이 데몬을 실행할 수 있다.

$ sudo systemctl enable celery
$ sudo systemctl start celery

위 명령어로 시작하기 전에 반드시 django 앱 및 celery 설정이 올바르게 되어 있어야 한다.

만약 celery.service 파일을 수정하고 재시작하려면 아래와 같이 명령한다.

$ sudo systemctl daemon-reload
$ sudo systemctl restart celery

최종 수정일시: 2019-01-24 02:01

blog comments powered by Disqus