[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