on
[error][미해결]django, celery, compose 이메일 보내기
[error][미해결]django, celery, compose 이메일 보내기
- 프로젝트 구성 환경 :
- linux alpine docker container
- docker-compose로 stack 구성
- celery-worker, redis-broker, django container, postgres db container
-
- 구현 하려는 것 :
- 일시 : 2021-10-21 (목)
- 마지막 error log sentences:
```python
...
...
kombu.exceptions.EncodeError: Object of type Request is not JSON serializable
HTTP POST /auth/signup 500 [0.34, 192.168.21.73:56863]
```
- 오류 추정 : json으로 직렬화가 필요한 것 같은 느낌. task 함수에 넘기기 위한 데이터를 json으로 바꿔서 넘김
- 전체 error log :
```python
stt_api | Traceback (most recent call last):
stt_api | File "/usr/local/lib/python3.9/site-packages/asgiref/sync.py", line 482, in thread_handler
stt_api | raise exc_info[1]
stt_api | File "/usr/local/lib/python3.9/site-packages/django/core/handlers/exception.py", line 38, in inner
stt_api | response = await get_response(request)
stt_api | File "/usr/local/lib/python3.9/site-packages/django/core/handlers/base.py", line 233, in _get_response_async
stt_api | response = await wrapped_callback(request, *callback_args, **callback_kwargs)
stt_api | File "/usr/local/lib/python3.9/site-packages/asgiref/sync.py", line 444, in __call__
stt_api | ret = await asyncio.wait_for(future, timeout=None)
stt_api | File "/usr/local/lib/python3.9/asyncio/tasks.py", line 442, in wait_for
stt_api | return await fut
stt_api | File "/usr/local/lib/python3.9/concurrent/futures/thread.py", line 52, in run
stt_api | result = self.fn(*self.args, **self.kwargs)
stt_api | File "/usr/local/lib/python3.9/site-packages/asgiref/sync.py", line 486, in thread_handler
stt_api | return func(*args, **kwargs)
stt_api | File "/usr/local/lib/python3.9/site-packages/django/views/decorators/csrf.py", line 54, in wrapped_view
stt_api | return view_func(*args, **kwargs)
stt_api | File "/usr/local/lib/python3.9/site-packages/django/views/generic/base.py", line 70, in view
stt_api | return self.dispatch(request, *args, **kwargs)
stt_api | File "/usr/local/lib/python3.9/site-packages/rest_framework/views.py", line 509, in dispatch
stt_api | response = self.handle_exception(exc)
stt_api | File "/usr/local/lib/python3.9/site-packages/rest_framework/views.py", line 469, in handle_exception
stt_api | self.raise_uncaught_exception(exc)
stt_api | File "/usr/local/lib/python3.9/site-packages/rest_framework/views.py", line 480, in raise_uncaught_exception
stt_api | raise exc
stt_api | File "/usr/local/lib/python3.9/site-packages/rest_framework/views.py", line 506, in dispatch
stt_api | response = handler(request, *args, **kwargs)
stt_api | File "/app/src/users/views.py", line 39, in post
stt_api | send_email.apply_async((request, user, token), serializer='json')
stt_api | File "/usr/local/lib/python3.9/site-packages/celery/app/task.py", line 572, in apply_async
stt_api | return app.send_task(
stt_api | File "/usr/local/lib/python3.9/site-packages/celery/app/base.py", line 767, in send_task
stt_api | amqp.send_task_message(P, name, message, **options)
stt_api | File "/usr/local/lib/python3.9/site-packages/celery/app/amqp.py", line 510, in send_task_message
stt_api | ret = producer.publish(
stt_api | File "/usr/local/lib/python3.9/site-packages/kombu/messaging.py", line 166, in publish
stt_api | body, content_type, content_encoding = self._prepare(
stt_api | File "/usr/local/lib/python3.9/site-packages/kombu/messaging.py", line 254, in _prepare
stt_api | body) = dumps(body, serializer=serializer)
stt_api | File "/usr/local/lib/python3.9/site-packages/kombu/serialization.py", line 213, in dumps
stt_api | payload = encoder(data)
stt_api | File "/usr/local/lib/python3.9/contextlib.py", line 137, in __exit__
stt_api | self.gen.throw(typ, value, traceback)
stt_api | File "/usr/local/lib/python3.9/site-packages/kombu/serialization.py", line 46, in _reraise_errors
stt_api | reraise(wrapper, wrapper(exc), sys.exc_info()[2])
stt_api | File "/usr/local/lib/python3.9/site-packages/kombu/exceptions.py", line 21, in reraise
stt_api | raise value.with_traceback(tb)
stt_api | File "/usr/local/lib/python3.9/site-packages/kombu/serialization.py", line 42, in _reraise_errors
stt_api | yield
stt_api | File "/usr/local/lib/python3.9/site-packages/kombu/serialization.py", line 213, in dumps
stt_api | payload = encoder(data)
stt_api | File "/usr/local/lib/python3.9/site-packages/kombu/utils/json.py", line 68, in dumps
stt_api | return _dumps(s, cls=cls or _default_encoder,
stt_api | File "/usr/local/lib/python3.9/json/__init__.py", line 234, in dumps
stt_api | return cls(
stt_api | File "/usr/local/lib/python3.9/json/encoder.py", line 199, in encode
stt_api | chunks = self.iterencode(o, _one_shot=True)
stt_api | File "/usr/local/lib/python3.9/json/encoder.py", line 257, in iterencode
stt_api | return _iterencode(o, 0)
stt_api | File "/usr/local/lib/python3.9/site-packages/kombu/utils/json.py", line 58, in default
stt_api | return super().default(o)
stt_api | File "/usr/local/lib/python3.9/json/encoder.py", line 179, in default
stt_api | raise TypeError(f'Object of type {o.__class__.__name__} '
stt_api | kombu.exceptions.EncodeError: Object of type Request is not JSON serializable
stt_api | HTTP POST /auth/signup 500 [0.34, 192.168.21.73:56863]
```
- 시도한 방법
- settings.py 파일 수정
```python
CELERY_BROKER_URL = os.environ.get("CELERY_BROKER", "redis://127.0.0.1:6379/0")
CELERY_RESULT_BACKEND = os.environ.get("CELERY_BACKEND", "redis://127.0.0.1:6379/0")
CELERY_TIMEZONE = "Asia/Seoul"
CELERY_TASK_TRACK_STARTED = True
CELERY_TASK_TIME_LIMIT = 30 * 60
CELERY_ACCEPT_CONTENT = ['json']
CELERY_RESULT_SERIALIZER = ['json']
CELERY_TASK_SERIALIZER = ['json']
```
```users/task.py
from celery import shared_task
from django.conf import settings
from django.core.mail import send_mail
from django.contrib.sites.shortcuts import get_current_site
from django.urls import reverse
@shared_task
def send_email(email_arg):
request = email_arg['request']
user = email_arg['user']
token = email_arg['token']
current_site = get_current_site(request).domain
relativeLink = reverse('email-verify')
absurl = f'http://{current_site}{relativeLink}?token={token}'
subject = 'Hello Please Verify your email'
body = f'Hi {user.username}! Click link below to verify your account.
{absurl}'
send_mail(
subject=subject,
message=body,
from_email='[email protected]',
recipient_list=[user.email],
fail_silently=False
)
return {'message': 'Successfully Emailed'}
```
```users/views.py
import jwt
import json
from django.conf import settings
from rest_framework import permissions
from rest_framework import generics, status, views
from rest_framework.response import Response
from rest_framework_simplejwt.tokens import RefreshToken
from smtplib import SMTPException
from drf_yasg.utils import swagger_auto_schema
from drf_yasg import openapi
from .serializers import (
RegisterSerializer, EmailVerificationSerializer, LoginSerializer, ListUserSerializer
)
from .models import User
from .utils import Util
from .permissions import IsOwner
from .task import send_email
class RegisterUserView(generics.GenericAPIView):
serializer_class = RegisterSerializer
def post(self, request):
try:
user = request.data
serializer = self.serializer_class(data=user)
serializer.is_valid(raise_exception=True) # validate() 메소드를 호출함
serializer.save()
user = User.objects.get(email=serializer.data['email'])
token = RefreshToken.for_user(user).access_token
email_arg = {'request':request, 'user':user, 'token':token}
send_email.apply_async(args=json.dumps(email_arg))
return Response(serializer.data, status=status.HTTP_201_CREATED)
except User.DoesNotExist:
return Response(serializer.errors, status=status.HTTP_404_NOT_FOUND)
except SMTPException as e:
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
```
- 결과 : 여전히 동일한 오류 발생
```python
stt_api | Traceback (most recent call last):
stt_api | File "/usr/local/lib/python3.9/site-packages/asgiref/sync.py", line 482, in thread_handler
stt_api | raise exc_info[1]
stt_api | File "/usr/local/lib/python3.9/site-packages/django/core/handlers/exception.py", line 38, in inner
stt_api | response = await get_response(request)
stt_api | File "/usr/local/lib/python3.9/site-packages/django/core/handlers/base.py", line 233, in _get_response_async
stt_api | response = await wrapped_callback(request, *callback_args, **callback_kwargs)
stt_api | File "/usr/local/lib/python3.9/site-packages/asgiref/sync.py", line 444, in __call__
stt_api | ret = await asyncio.wait_for(future, timeout=None)
stt_api | File "/usr/local/lib/python3.9/asyncio/tasks.py", line 442, in wait_for
stt_api | return await fut
stt_api | File "/usr/local/lib/python3.9/concurrent/futures/thread.py", line 52, in run
stt_api | result = self.fn(*self.args, **self.kwargs)
stt_api | File "/usr/local/lib/python3.9/site-packages/asgiref/sync.py", line 486, in thread_handler
stt_api | return func(*args, **kwargs)
stt_api | File "/usr/local/lib/python3.9/site-packages/django/views/decorators/csrf.py", line 54, in wrapped_view
stt_api | return view_func(*args, **kwargs)
stt_api | File "/usr/local/lib/python3.9/site-packages/django/views/generic/base.py", line 70, in view
stt_api | return self.dispatch(request, *args, **kwargs)
stt_api | File "/usr/local/lib/python3.9/site-packages/rest_framework/views.py", line 509, in dispatch
stt_api | response = self.handle_exception(exc)
stt_api | File "/usr/local/lib/python3.9/site-packages/rest_framework/views.py", line 469, in handle_exception
stt_api | self.raise_uncaught_exception(exc)
stt_api | File "/usr/local/lib/python3.9/site-packages/rest_framework/views.py", line 480, in raise_uncaught_exception
stt_api | raise exc
stt_api | File "/usr/local/lib/python3.9/site-packages/rest_framework/views.py", line 506, in dispatch
stt_api | response = handler(request, *args, **kwargs)
stt_api | File "/app/src/users/views.py", line 40, in post
stt_api | send_email.apply_async(args=json.dumps(email_arg))
stt_api | File "/usr/local/lib/python3.9/json/__init__.py", line 231, in dumps
stt_api | return _default_encoder.encode(obj)
stt_api | File "/usr/local/lib/python3.9/json/encoder.py", line 199, in encode
stt_api | chunks = self.iterencode(o, _one_shot=True)
stt_api | File "/usr/local/lib/python3.9/json/encoder.py", line 257, in iterencode
stt_api | return _iterencode(o, 0)
stt_api | File "/usr/local/lib/python3.9/json/encoder.py", line 179, in default
stt_api | raise TypeError(f'Object of type {o.__class__.__name__} '
stt_api | TypeError: Object of type Request is not JSON serializable
stt_api | HTTP POST /auth/signup 500 [0.21, 192.168.21.73:49673]
```
from http://hyeseong-dev.tistory.com/2 by ccl(A) rewrite - 2021-10-21 12:01:08