kombu.exceptions.EncodeError: User 不是 JSON 可序列化的



我有带有芹菜 4.1.0 的 django 1.11.5 应用程序,我一直收到:

kombu.exceptions.EncodeError: <User: testuser> is not JSON serializable

我 settings.py:

CELERY_BROKER_URL = 'amqp://localhost'
CELERY_RESULT_BACKEND = 'amqp://localhost'
CELERY_ACCEPT_CONTENT = ['application/json']
CELERY_RESULT_SERIALIZER = 'json'
CELERY_TASK_SERIALIZER = 'json'
CELERY_TIMEZONE = 'Asia/Makassar'
CELERY_BEAT_SCHEDULE = {}

tasks.py

from __future__ import absolute_import, unicode_literals
from celery import task
from django.contrib.auth.models import User

@task(serializer='json')
def task_number_one():
    user = User.objects.create(username="testuser", email="test@test.com", password="pass")
    return user

我在视图中调用任务:

def form_valid(self, form):
    form.instance.user = self.request.user
    task_number_one.delay()
    return super().form_valid(form)
这是因为

您正在使用 JSON 序列化程序进行任务序列化(如设置 CELERY_TASK_SERIALIZER = 'json' 所示(,但您正在尝试返回模型实例(无法序列化为 JSON(。

您有两种选择:

1(不要传递实例,传递实例的主键,然后在任务中查找对象。

2( 请改用pickle任务序列化程序。这将允许您将对象作为参数传递给您的任务并返回它们,但伴随着它自身的安全问题。

此错误是因为 Celery 在您返回User实例时期望从您的任务函数获得JSON数据。

如何解决这个问题?
您没有在任何地方使用该返回数据,因此您不必返回它。也就是说,您可以从任务功能中删除return user

从任务函数返回Json数据也将

解决此问题解决方案 1

@task(serializer='json')
def task_number_one():
    user = User.objects.create(username="testuser", email="test@test.com", password="pass")


解决方案 2

@task(serializer='json')
def task_number_one():
    user = User.objects.create(username="testuser", email="test@test.com", password="pass")
    # return some json data instead of `USER` instance
    return {"status": True}  # Change is here

我的芹菜任务:

response = {}
...
except HTTPError as e:
        response.update(
            {
                'status': False,
                'code': e.status_code,
                'error': e.body,
            },
        )
    ...
return response

我有EncodeError(TypeError('Object of type bytes is not JSON serializable')kombu.exceptions.EncodeError,尽管响应是一个dict,在 JSON 编码时应该不是问题。

事实证明,e.body是字节类型。我改e.body.decode('utf-8'),问题消失了。

另一个与这个问题无关但也有用的答案

如果将 OBJ 传递给任务,可能会得到相同的错误信息,那么您可以:

@shared_task(serializer="pickle")
def email_send_task(msg: EmailMultiAlternatives):
    try:
        msg.send()
    except (smtplib.SMTPException, TimeoutError) as e:
        return f"Email failed with {e}"

对于以下配置:

  1. 姜戈==3.0.11
  2. 雷迪斯==2.10.6
  3. 芹菜==4.0.0
  4. 昆布==4.0.0

我在 settings.py 文件上更新了以下配置,它起作用了。

CELERY_SETTINGS = {
    'CELERY_TIMEZONE': TIME_ZONE,
    'CELERY_ENABLE_UTC': True,
    'CELERY_RESULT_BACKEND': REDIS_URL,
    'CELERY_SEND_TASK_SENT_EVENT': True,
    'CELERY_TASK_SERIALIZER': 'pickle',
    'CELERY_RESULT_SERIALIZER': 'pickle',
    'CELERY_ACCEPT_CONTENT': ['pickle', 'json'],
}

不要忘记更新TIME_ZONE的实际值和REDIS_URL

原因可能是 Celery 4 版本默认使用 JSON 作为序列化程序,而 celery3 版本默认使用 Pickle。

旧的 Django 可能不希望任务采用 JSON 格式。所以,如果你使用的是非常旧的Django版本,这可能会帮助你。

相关内容

  • 没有找到相关文章

最新更新