Django DRF集成Celery+Redis调用delay触发Response对象无法JSON序列化报错
错误产生原因
你遇到的报错:
EncodeError(TypeError('Object of type Response is not JSON serializable'))
该报错本质是Celery序列化环节出现了不可序列化的对象,核心原因如下:
- Celery默认对任务的入参、返回值都要求是可JSON序列化的原生数据类型,你初始代码中直接将
serializer序列化器实例作为参数传入delay方法,这类DRF类实例无法被JSON序列化,Celery需要将参数序列化后存入Broker(Redis),因此直接触发序列化报错。 - 你修改入参为字典后仍报错,常见原因如下:
- 你没有删除初始代码中第二行传入serializer的
test_call.delay调用,两次调用中第二次无效调用仍然会触发报错 - 你的Celery配置中序列化相关参数异常,没有指定支持JSON序列化
- 存在同名任务覆盖问题,两个
@shared_task都指定了相同的name="values",后定义的任务会覆盖先定义的;且修改任务代码后没有重启Celery Worker,Worker仍在运行旧的错误逻辑 - 任务逻辑中存在返回不可序列化对象的情况,比如你不小心在任务中返回了DRF的
Response对象
- 你没有删除初始代码中第二行传入serializer的
解决方案
删除无效的任务调用,禁止直接传入类实例
删掉你初始代码中第二行的result = test_call.delay(serializer),永远不要直接将序列化器、模型实例、请求对象、文件对象等非原生类型作为Celery任务参数:- 如果需要用到序列化器的校验数据,传
serializer.validated_data即可 - 如果需要用到模型数据,传模型主键,在任务内部重新查询数据库获取实例即可
- 如果需要用到序列化器的校验数据,传
配置Celery序列化规则
在Django的settings.py中添加如下配置,明确指定序列化规则:
# 配置Celery序列化规则 CELERY_TASK_SERIALIZER = "json" CELERY_RESULT_SERIALIZER = "json" CELERY_ACCEPT_CONTENT = ["json"]
如果确实有需要传输复杂类型的场景,可以将序列化器改为pickle,但该方式存在安全风险,非必要不建议使用。
修复任务冲突并重启服务
修改任务的name参数保证全局唯一,每次修改任务代码后,必须重启Celery Worker进程,保证Worker加载最新的代码逻辑。检查任务返回值
保证任务的返回值都是可JSON序列化的原生类型,不要返回Response、类实例等不可序列化的对象。
内容的提问来源于stack exchange,提问作者Joseph Adam
相关产品推荐
相关产品推荐

