-
[Django] Django 연습장 - 7. 이메일 전송 비동기 방식 (celery + redis)프로그래밍/Django 2022. 4. 17. 02:15반응형
지난번 회원 가입 시 이메일 인증하는 프로세스를 추가했습니다.
그렇지만 문제가 있습니다.
이메일을 전송하는 함수는 다소 시간이 소요됩니다.
만약 이메일에 무언가를 첨부한다면 시간은 더욱 늘어납니다.
그러나 django는 Task들을 순서대로 처리합니다.
이 말은 앞에 일이 늦게 끝나면 뒤에 일 들도 처리가 늦어집니다.
이를 방지하기 위해 이메일 전송 및 시간이 오래 걸리는 작업들은 비동기 방식으로 처리합니다.
예를 들어 Event A, Event B 순서로 요청이 들어왔을 때 A->B 순서로 이루어지게 된다.
A의 처리가 늦어질수록 B의 처리에 영향이 간다.
그러나 비동기 방식으로 프로세스를 개선한다면 A의 처리완료 여부와 상관없이 B의 작업이 일어난다.
이를 위해서 사용하는 것이 Celery이다.
[작업내용]
- celery 설치 & 세팅
- celery.py
- 코드 변경 (task로 실행)
1. celery 설치 & 세팅 + redis (redis 모듈 설치를 해도 redis는 서버 따로 띄워줘야 함)
pip install celery pip install redis
settings.py
#celery CELERY_BROKER_URL = 'localhost:6379' CELERY_RESULT_BACKEND = 'localhost:6379' CELERY_ACCEPT_CONTENT = ['application/json'] CELERY_RESULT_SERIALIZER = 'json' CELERY_TASK_SERIALIZER = 'json' CELERY_TIMEZONE = TIME_ZONE
* redis는 docker로 띄웠음. docker-compose.yml 참고
version: '3.7' services: redis: container_name: redis image: redis:latest ports: - 6379:6379 restart: always volumes: - C:\<로컬 경로>:/data
2. config > celery.py
from __future__ import absolute_import, unicode_literals import os from celery import Celery os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings') # FIXME 추후 prod 변경 할것. app = Celery('config') app.config_from_object('django.conf:settings', namespace='CELERY') app.autodiscover_tasks() @app.task(bind=True) def debug_task(self): print(f'Request: {self.request!r}')
3. 기존 코드 변경
app_accounts > task.py
from celery import shared_task
#데코레이터추가 & retry @shared_task def task_send_register_mail(user, domain): try: template = 'mail_register.html' now_time = time.mktime(datetime.now().timetuple()) kwargs = { 'uid': urlsafe_base64_encode(force_bytes(user.id)), 'token': activate_token.make_token(user), 'time': int(now_time) } message = render_to_string(template, { 'user': user, 'domain': domain, 'kwargs' : kwargs, }) mail_subject = '회원가입 인증메일' to_email = [user.email] from_email = DEFAULT_FROM_EMAIL body = '' email = EmailMultiAlternatives(mail_subject, body, from_email, to_email) email.attach_alternative(message, "text/html") email.send() except User.DoesNotExist as e: task_send_register_mail.retry(countdown=1)
# 회원가입 class CreateAccounts(FormView): template_name = 'register.html' form_class = UserForm success_url = '/accounts/signin' def form_valid(self, form): password = make_password(form.data.get('password')) user = User( email=form.data.get('email'), password=password, nickname=form.data.get('nickname'), ) user.is_active = False user.save() #회원 가입 이메일 전송송 task_send_register_mail.delay(user, get_current_site(self.request).__str__()) return super().form_valid(form)
4. celery 실행 & 테스트
[실행]
celery -A config worker --pool=solo -l info
성공하면 이런 화면이 나옴
이제 회원가입을 해보겠음.
문제가 발생했음
기존에 user로 넘겨주던 객체가 celery로 변경하고 task.py를 나중에 실행하려니까 serializable하지 않은 데이터 형식이라 에러가 나타남
그래서 그냥 user_id를 넘겨주는 방식으로 코드 변경
app_accounts > views.py
user -> user.pk로 변경
class CreateAccounts(FormView): template_name = 'register.html' form_class = UserForm success_url = '/accounts/signin' def form_valid(self, form): password = make_password(form.data.get('password')) user = User( email=form.data.get('email'), password=password, nickname=form.data.get('nickname'), ) user.is_active = False user.save() #회원 가입 이메일 전송송 task_send_register_mail.delay(user.pk, get_current_site(self.request).__str__()) return super().form_valid(form)
redis 연결에서 문제가 있나 봄..
kombu.exceptions.OperationalError: [WinError 10061] 에러가 계속 발생함..
-> 한참을 리서치하다 보니 예전에도 같은 문제를 겪었었고
config 폴더의 __init__. py에
from __future__ import absolute_import, unicode_literals from .celery import app as celery_app __all__ = ('celery_app',)
해당 코드를 넣어주니 해결됐습니다.
django에서 celery를 인식하기 위해서 해당 코드를 입력해야 하고
이후 회원가입을 시도하니..
celery작업이 동작한 것을 확인할 수 있었습니다.
너무 예전 일이라서 까먹고 오래 삽질했지만 다시 해결할 수 있어서 다행입니다..!
반응형'프로그래밍 > Django' 카테고리의 다른 글
[Django] Django 연습장 - 6. 회원가입 프로세스 개선 (이메일 보내기 & 인증) (0) 2022.04.16 [Django] Django 연습장 - 5. html씌우기 (0) 2022.04.15 [Django] Django 연습장 - 4. 로그인 기능 만들기 (0) 2022.04.15 [Django] Django 연습장 - 3. User form 수정해서 회원 가입 조건 변경 (0) 2022.04.14 [Django] Django 연습장 - 2. User만들기 (1) 2022.04.14