Technique

웹서비스 비동기(백그라운드) 프로세스 만들기 (feat. Django, Celery) 4

JAY-GO 2018. 4. 5. 01:14
반응형

 3. Celery 셋팅

 이번 포스팅에서는 앞에서 작성해 놓은 django 앱에 비동기 프로세스를 위한 Celery를 적용해 보도록 하겠습니다. 이에 필요한 celery와 rabbitmq 패키지는 앞선 포스팅에서 이미 설치 하였습니다.


 ㅇ celery.py 생성

 celery를 사용하기 위해서는 django프로젝트의 프로젝트 폴더에 celery.py를 추가해야 합니다.

<mywebapp/celery.py>

from __future__ import absolute_import, unicode_literals
import os
from celery import Celery

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

app = Celery('applycelery')

# 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 app configs.
app.autodiscover_tasks()


@app.task(bind=True)
def debug_task(self):
print('Request: {0!r}'.format(self.request))

 - 우리는 docker에 필요한 패키지를 깔아두었기 때문에, 윈도우 환경인 ide환경에서는 celery의 import가 되지 않습니다. 경고 메시지가 떠도 걱정하지 않으셔도 됩니다.

 - os.environ.setdefault()에 django프로젝트의 settings를 연결 합니다.

 - app=Celery() 란에 앞에서 작성해둔 앱의 이름을 추가 하여 셀러리가 해당 앱에서 동작함을 정의합니다.


 ㅇ __init__.py 수정

 프로젝트 폴더의 __init__.py 에 필요한 내용을 추가 합니다.

<mywebapp/__init__.py>

from __future__ import absolute_import, unicode_literals

# 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']


 ㅇ tasks.py 만들기

 Celery를 통해 비동기로 동작할 Task(코드)들이 들어가는 파일 입니다. 아직은 공식 예제에 있는 기본 Task로 작성하였습니다. celery가 정상적으로 추가되었는지 확인 하고 필요한 코드를 작성해봅시다.

<applycelery/tasks.py>

# Create your tasks here
from __future__ import absolute_import, unicode_literals
from celery import shared_task


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


@shared_task
def mul(x, y):
return x * y


@shared_task
def xsum(numbers):
return sum(numbers)


 ㅇ Celery 작동 확인

 지금까지 셋팅한 celery가 동작하는지 확인 해보겠습니다. docker 컨테이너의 콘솔(exec) 버튼 으로 컨테이너로 들어가서 celery를 구동하여 보겠습니다.

# celery -A mywebapp worker -l info

/usr/local/lib/python3.6/dist-packages/celery/platforms.py:795: RuntimeWarning: You're running the worker with superuser privileges: this is

absolutely not recommended!


Please specify a different user using the -u option.


User information: uid=0 euid=0 gid=0 egid=0


  uid=uid, euid=euid, gid=gid, egid=egid,


 -------------- celery@629b4d182cdc v4.1.0 (latentcall)

---- **** -----

--- * ***  * -- Linux-4.4.89-boot2docker-x86_64-with-Ubuntu-18.04-bionic 2018-04-06 23:01:05

-- * - **** ---

- ** ---------- [config]

- ** ---------- .> app:         applycelery:0x7f282b6654a8

- ** ---------- .> transport:   amqp://guest:**@localhost:5672//

- ** ---------- .> results:     disabled://

- *** --- * --- .> concurrency: 1 (prefork)

-- ******* ---- .> task events: OFF (enable -E to monitor tasks in this worker)

--- ***** -----

 -------------- [queues]

                .> celery           exchange=celery(direct) key=celery



[tasks]

  . applycelery.tasks.add

  . applycelery.tasks.mul

  . applycelery.tasks.xsum

  . mywebapp.celery.debug_task 

 정상적으로 셋팅이 완료 되었다면 위와같은 화면이 나타납니다. 이후 계속적으로 error 메시지가 작동 합니다. 이는 celery와 연동할 브로커인 rabbitmq를 동작시키지 않아 발생하는 메시지 입니다.

 하단의 [tasks]를 오면 tasks.py에 작성해 놓은 task 들이 나타납니다. 정상적으로 celery가 동작하고 있음을 확인할 수 있습니다.


4. celery 적용

 이제 4개의 버튼중 정의 안된 2개의 버튼에 들어갈 기능을 celery로 구현 해 봅시다.


 ㅇ celery task 정의

 celery에서 동작하는 task를 작성해 봅시다. 기본적으로 django view에 동작하는 코드와 유사하게 만들어 같은 코드가 동기로 동작하는 것과 비동기로 동작하는 것을 비교하고자 합니다.

 앞에서 준비한 task.py를 수정 합니다.

<applycelery/task.py>

# Create your tasks here
from __future__ import absolute_import, unicode_literals
from celery import shared_task
from .models import operate_time
from django.utils import timezone
import time


@shared_task
def celery():
click_command = "celery"
click_time = timezone.now()
done_time = timezone.now()
time_gap = done_time - click_time
form_new = operate_time(click_time=click_time, done_time=done_time, time_gap=time_gap, click_command=click_command)
form_new.save()

@shared_task
def celery_delay():
click_command = "celery_delay"
click_time = timezone.now()
time.sleep(10)
done_time = timezone.now()
time_gap = done_time - click_time
form_new = operate_time(click_time=click_time, done_time=done_time, time_gap=time_gap, click_command=click_command)
form_new.save()


 ㅇ view에 적용

 위에서 작성한 celery task를 django view에 연결 해줍니다. 해당 task를 비동기로 사용하기 위해서는 .delay()로 동작 시켜야 합니다. 만약 이를 포함하지 않으면 보통의 함수 호출과 같이 동기식으로 동작하게 됩니다.

<applycelery/views.py>

from django.shortcuts import render
from .models import operate_time
from .tasks import celery, celery_delay
from django.utils import timezone
import time

# Create your views here.

def app_core(request):
operate_list = operate_time.objects.order_by('-id').all()
if (request.GET.get('operate')):
click_command = "operate"
click_time = timezone.now()
done_time = timezone.now()
time_gap = done_time-click_time
form_new = operate_time(click_time=click_time, done_time=done_time, time_gap=time_gap, click_command=click_command)
form_new.save()

if (request.GET.get('operate_delay')):
click_time = timezone.now()
time.sleep(10)
done_time = timezone.now()
time_gap = done_time-click_time
click_command = "operate"
form_new = operate_time(click_time=click_time, done_time=done_time, time_gap=time_gap, click_command=click_command)
form_new.save()

if (request.GET.get('celery')):
celery.delay()

if (request.GET.get('celery_delay')):
celery_delay.delay()


return render(request, 'django_celery_main.html', {'operate_list': operate_list})

 tasks.py에 정의된 task 들을 import 하고 해당 조건문에서 .delay()로 호출 하였습니다.


이제 필요한 셋팅 및 코드 작성을 마쳤습니다. 다음 포스팅에서는 celery 및 기타 필요한 페키지들을 동작시켜 celery동작을 확인하고 celery에 의한 비동기 동작을 직접 경험해 보도록 하겠습니다.

반응형