如何序列化二进制文件以用于芹菜任务

Amy*_*yth 8 django binaryfiles pickle celery

我最近在我的一个应用程序中集成了芹菜(django-celery更具体).我在应用程序中有一个模型如下.

class UserUploadedFile(models.Model)
    original_file = models.FileField(upload_to='/uploads/')    
    txt = models.FileField(upload_to='/uploads/')
    pdf = models.FileField(upload_to='/uploads/')
    doc = models.FileField(upload_to='/uploads/')

    def convert_to_others(self):
        # Code to convert the original file to other formats
Run Code Online (Sandbox Code Playgroud)

现在,一旦用户上传文件,我想将原始文件转换为txt,pdf和doc格式.调用该convert_to_others方法是一个昂贵的过程,所以我打算使用芹菜异步.所以我写了一个简单的芹菜任务如下.

@celery.task(default_retry_delay=bdev.settings.TASK_RETRY_DELAY)
def convert_ufile(file, request):
    """ 
    This task method would call a UserUploadedFile object's convert_to_others
    method to do the file conversions.

    The best way to call this task would be doing it asynchronously
    using apply_async method.
    """
    try:
        file.convert_to_others()
    except Exception, err:
        # If the task fails log the exception and retry in 30 secs
        log.LoggingMiddleware.log_exception(request, err)
        convert_ufile.retry(exc=err)
    return True
Run Code Online (Sandbox Code Playgroud)

然后调用任务如下:

ufile = get_object_or_404(models.UserUploadedFiles, pk=id)
tasks.convert_ufile.apply_async(args=[ufile, request])
Run Code Online (Sandbox Code Playgroud)

现在,当apply_async调用该方法时,它会引发以下异常:

PicklingError: Can't pickle <type 'cStringIO.StringO'>: attribute lookup cStringIO.StringO failed
Run Code Online (Sandbox Code Playgroud)

我认为这是因为芹菜(默认情况下)使用pickle库来序列化数据,而pickle无法序列化二进制文件.

是否还有其他可以自行序列化二进制文件的序列化程序?如果不是,我如何使用默认pickle序列化器序列化二进制文件?

dzi*_*ida 5

你是正确的,芹菜试图挑选不支持酸洗的数据.即使你找到一种方法来序列化你想要发送给芹菜任务的数据,我也不会这样做.

将尽可能少的数据发送到芹菜任务总是一个好主意,所以在你的情况下我只传递UserUploadedFile实例的id .有了这个,你可以在芹菜任务中通过id获取你的对象并执行convert_to_others().

还请注意,在执行任务之前,对象可以更改其状态(或甚至可以删除).因此,在芹菜任务中获取对象而不是发送完整副本更安全.

总而言之,只发送一个实例ID并在任务中重新获取它会给你一些东西:

  • 您向队列发送的数据较少.
  • 您不必处理数据不一致问题.
  • 在你的情况下,它实际上是可能的.:)

唯一的"缺点"是,与上述问题相比,您需要执行额外的,廉价的SELECT查询来重新获取数据,总体看起来很划算,不是吗?

  • 如果我正确理解您的答案,如果您想扩展,这将不起作用。如果您的 Django 应用程序和 Celery 在同一台机器上运行,您将能够访问 UserUploadFile 实例*和*实际的磁盘文件。如果您有单独的 Celery 节点,它们将无法访问磁盘文件。Django 不在数据库中存储文件。这可能是一个糟糕的解决方案,但我对二进制文件进行了 uuencode,并将 uuencoded 数据保存到 TextField 中。 (2认同)