코딩 개발일지

django(DRF)+Celery+RabbitMQ (이메일 인증) 본문

AI 본 교육/AI 13주차

django(DRF)+Celery+RabbitMQ (이메일 인증)

호기호 2023. 11. 8. 18:28

 

Celery는 일꾼이다.

처리할 일을 큐로 쌓아두면, Celery가 가져다가 일처리를 한다. (파이썬 언어 사용)

pip install celery
pip install django-celery-results

(celery 모듈 설치)

(+ 결과를 DB에 저장하기위한 app)

※  local 에서는 이메일이 잘 갔는지 확인 가능하지만, 실제 서비스 할 때, 정상적으로 보냈는지 확인하려면 DB에 저장해야 한다. ※


RabbitMQ 는 주인이다. (브로커 역할)

django에서 일거리를 주면, Celery 한테 일하라고 던져준다.

우리는 RabbitMQ는 일처리를 하는 브로커역할이다.


RabbitMQ

메시지 브로커이다.
app과 메시지를 주고 받을 수 있고, 메시지가 수신될 때까지 안전하게 있을 수 있도록 하는 공용 플래폼을 제공한다.


- 메시지를 다른 대기열로 보낼 수있는 시스템을 갖추고 있다.
- 우선 순위가 높은 메시지를 먼저 사용하기 위해 작업자가 사용할 수있는 메시지의 우선 순위를 지원한다.
- 메시지 브로커로서 Redis와 비교할 때 훨씬 더 다양한 기능을 제공한다.


크고 복잡한 메시지에 적합하기 때문에 저장보다는 좀 더 복잡한 이메일을 보내주는 기능에 사용했다 !!!

또한 추후에 이메일 인증 뿐만 아니라, 문자메시지 전송과 같은 다양한 기능이 추가될 수 있어서 채택했다.


리눅스를 이용하는게 정석이지만, 쉽고 보기 편한 docker desktop을 이용했다.

https://www.docker.com/products/docker-desktop/    ☢️ 설치 후 재부팅 주의 ☢️

나중에 실행시키고 VSCode 터미널에서 rabbitmq 실행시키면 알아서 docker desktop에 추가된다.

(개꿀)

이 명령어는 나중에 알아보도록 하자


먼저 settings.py에 여러가지 추가해주자.

INSTALLED_APPS = [
    'django_celery_results',
]

결과를 db에 저장하기위해 app 추가.

MAIL_HOST = env('EMAIL_HOST')
EMAIL_HOST_USER = env('EMAIL_HOST_USER')
EMAIL_HOST_PASSWORD = env('EMAIL_HOST_PASSWORD')
EMAIL_USE_TLS = env('EMAIL_USE_TLS')
DEFAULT_FROM_EMAIL = EMAIL_HOST_USER

요기까지는 이전의 글인 동기방식의 이메일 인증이다. (Celery 사용 안함)

그리고 EMAIL_HOST_PASSWORD 와 같은 보안이 중요한 정보는 .env파일에 관리를 했다.

⭐Trouble Shooting  더보기 클릭

더보기

<.env>

EMAIL_HOST_USER = '????????@gmail.com'
EMAIL_HOST_PASSWORD = 'aaaa bbbb cccc dddd'

이 때, 매우 신경쓰이는 오류가 발생했다!!!!!!!! 뭘까유?

이렇게 작성해도 이메일 인증기능은 정상적으로 작동하는데, 터미널에서 invalid line에러가 발생했다.

invalid line : EMAIL_HOST_USER

invalid line : EMAIL_HOST_PASSWORD

.env 파일에서 = 의 앞, 뒤에는 공백이 없어야한다. 공백 지워주니 해결 완료.


CELERY_BROKER_URL = 'amqp://guest@localhost:5672//'

이메일 인증을 보내주는 역할을 하는 rabbitmq를 사용하기위해 이렇게 작성해준다.

CELERY_TIMEZONE = 'Asia/Seoul'
CELERY_RESULT_BACKEND = 'django-db'
CELERY_ACCEPT_CONTENT = ['application/json']
CELERY_TASK_SERIALIZER = 'json'
CELERY_RESULT_SERIALIZER = 'json'

CELERY_RESULT_EXPIRES = 3600
CELERY_RESULT_EXTENDED = True               # log 정보를 더 세밀하게 출력한다.
CELERY_CACHE_BACKEND = 'default'
CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.db.DatabaseCache',
        'LOCATION': 'my_cache_table',
    }
}

django_celery_results를 사용하기 때문에, django DB 에 저장하고, django의 cache를 사용한다.

queue 작업 데이터를 json화 하는 설정을 해줬다.

결과값은 3600초 후에 사라지도록 설정했는데, 잘 작동되지 않았다...ㅠㅠ 뭘까.. 나중에 추가하겠음.

⭐Trouble Shooting  더보기 클릭

더보기

추후에 모든 기능을 완성 후, 온갖 방법을 사용해봤지만, 정상 작동되지 않았다.

아주 허무하겠지만, 결론적으로 말하자면, migrate를 새로 해줘야 했다.

installed apps에 추가하면 무조건 migrate 새로 해줘야 한다는 사실을 알았다...

 

전 migrate는 models.py 가 바뀔 때만 해주는줄 알았당 ㅠㅠ 생각해보니 꽤나...? 당연한 소리였다...!!


<celery.py> 파일을 settings.py와 같은 directory에 만들어주고, 아래와 같이 작성했다.

참고로 우리 프로젝트명은 yummy_yagi 이다. 알아서 바꿔서 쓰도록 하십숑~

import os
from django.conf import settings
from celery import Celery


os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'yummy_yagi.settings')

app = Celery('yummy_yagi', broker=settings.CELERY_BROKER_URL, backend=settings.CELERY_RESULT_BACKEND, include=['user.tasks'])

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

app.conf.update(result_expires=settings.CELERY_RESULT_EXPIRES,)

if __name__ == '__main__':
    app.start()

app.autodiscover_tasks(lambda: settings.INSTALLED_APPS)

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

그리고 동일한 directory에 있는 파일인 <__init__.py>에 아래와 같이 작성한다.

from .celery import app as celery_app

__all__ = ('celery_app',)

이제, 회원가입 기능과 이메일 인증 기능이 있는 app 의 directiory에 <tasks.py>를 생성 후 아래와 같이 작성한다.

from celery import shared_task
from django.core.mail import send_mail

@shared_task
def send_verification_email(user_id, verification_url, recipient_email):
    subject = '이메일 확인 링크'
    message = f'이메일 확인을 완료하려면 다음 링크를 클릭하세요: {verification_url}'
    from_email = ' ????????@gmail.com '
    print(f'subject:{subject}')
    send_mail(subject, message, from_email, [recipient_email])

이후, 회원가입하는 기능에 추가해주면 된다.

이메일 인증을 동기방식으로 한 이전 글을 꼭 보고 오시길 추천드립니당..

<views.py>

from .tasks import send_verification_email

tasks.py import 해주구요~

class RegisterView(APIView):
    def post(self, request):
        if request.data['password'] != request.data['password_check']:
            return Response({'status':'400', 'error':'비밀번호를 확인해주세요.'}, status=status.HTTP_400_BAD_REQUEST)
        else:
            serializer = UserSerializer(data=request.data)
            if serializer.is_valid():
                user=serializer.save()
 
                token = default_token_generator.make_token(user)
                uid = urlsafe_base64_encode(force_bytes(user.pk))
 
                verification_url = f'http://127.0.0.1:8000/user/verify-email/{uid}/{token}/'
                send_verification_email.delay(user.id, verification_url, user.email)
               
                return Response({'status':'201', 'success':'회원가입 성공'}, status=status.HTTP_201_CREATED)
 
            return Response({'status':'400', 'error':serializer.errors}, status=status.HTTP_400_BAD_REQUEST)


class VerifyEmailView(APIView):
    def get(self, request, uidb64, token):
        uid = urlsafe_base64_decode(uidb64)
        user = User.objects.get(id=uid)

        if default_token_generator.check_token(user, token):
            user.is_active = True
            user.save()
        return Response(status=status.HTTP_200_OK)

기존에는 이메일을 보내는 함수를 따로 정의해줬는데, 그걸 tasks.py에 넣고, 회원가입 기능과 합쳤다.

 

기존의 코드와 비슷한데, 다른 부분은 send_verification_email.delay

'delay'는 Celery 작업을 예약하여 나중에 백그라운드에서 비동기적으로 실행되도록 하는 메소드이다.


자, 이제 기능구현은 다했으니, RabbitMQ 실행 후, Celery 실행하고, 회원가입을 진행해보자.

 

먼저, 아까 설치한 Docker Desktop을 실행해주고, vscode 터미널에서 이렇게 작성해주자.

< rabbitmq 서버 실행 >

docker run -d -p 5672:5672 rabbitmq

이걸 입력하면, Docker Desktop에 추가되는것을 볼 수 있다.


celery 실행해주자.

 

MAC 사용자 : 

celery -A yummy_yagi worker -l info

윈도우 사용자 : eventlet 설치 해줘야함.

pip install eventlet

celery -A yummy_yagi worker -l info -P eventlet

터미널을 확인해보면, Celery가 잘 실행된것을 볼 수 있다.

이 상태에서 postman으로 회원가입을 진행해주니, DB에도 결과값이 잘 들어갔고, 이메일 인증 기능도 잘 작동했다.

1~4 번은 실패의 흔적..

구웃~

'AI 본 교육 > AI 13주차' 카테고리의 다른 글

DRF 로그인 / 회원탈퇴  (0) 2023.11.07
python의 장점과 단점 / 파이썬은 느리다??  (0) 2023.11.06