在尝试将文件传递给Celery任务时,有时会出现异常"无法序列化"_io.BufferedReader"对象"。这种情况似乎发生在某些文件中,而不是其他文件中。端点是一个APIView,其中包含以下内容以启动任务:
from celery import signature
task = signature(
data.get('action'),
kwargs={'data': data,
'authorization': authorization,
"files": files}
).apply_async()
当一些文件包含在请求中时,它确实可以正常工作,但会为其他文件抛出异常。
阻止程序是FileHandler。当上传一个更大的文件时,Django会调用TemporaryFileUploadHandler来创建一个TemporaryUploadedFile,该文件存储并从磁盘流式传输。这种类型的文件不可由pickle序列化,因此pickle/kombu抛出";无法序列化"_io.BufferedReader"对象"例外
解决方案是将settings.py中的FILE_UPLOAD_MAX_MEMORY_SIZE
的值设置为一个高值(100MB(,这样大文件(<100MB(就会变成InMemoryUploadedFiles,并在视图中写入一个检查,返回一个更有用的错误:
from rest_framework.response import Response
from rest_framework.status import HTTP_413_REQUEST_ENTITY_TOO_LARGE
from django.core.files.uploadedfile import TemporaryUploadedFile
# If it is not an in memory file, we cannot pickle it.
if any([isinstance(x, TemporaryUploadedFile) for x in files.values()]):
return Response(
'File too large to upload.',
status=HTTP_413_REQUEST_ENTITY_TOO_LARGE
)
虽然不能100%确定HTTP413是最合适的状态代码,但它对我来说是有意义的,而且描述也应该有助于最终用户。