【问题标题】:Django and Celery: unable to pickle taskDjango和Celery:无法腌制任务
【发布时间】:2013-08-15 05:01:37
【问题描述】:

提前致谢:)

我有这个异步 Celery 任务调用:

update_solr.delay(id, context)

其中 id 是一个整数,context 是一个 Python 字典。

我的任务定义如下:

@task
def update_solr(id, context):
    clip = Clip.objects.get(pk=id)
    clip_serializer = SOLRClipSerializer(clip, context=context)
    response = requests.post(url, data=clip_serializer.data)

clip_serializer.data 是一个字典,url 是一个代表 url 的字符串。

当我尝试拨打 update_solr.delay() 时,我收到此错误:

PicklingError: Can't pickle <type 'instancemethod'>: attribute lookup __builtin__.instancemethod failed

任务的参数都不是实例方法,所以我很困惑。

任务代码同步运行时,没有报错。

更新:每个 cmets 修复了关于传递 pk 而不是对象的问题。

【问题讨论】:

  • 为了避免竞争条件并减少有效负载大小,最好传递模型 PK 而不是模型实例。
  • 完全正确,但不能解决问题。
  • 对象中的某些东西是 实例方法(也就是说,您将 Object.foomethod 放在字典中,或类似的东西中),在一个 pickle 无法腌制它的地方。
  • 可能没有定义任务的完整定义为url?无法腌制异常,因此请尝试在不使用 Celery 的情况下运行该方法。
  • @AndrewS,这不是完整的定义,在代码中已经定义了。

标签: python django celery pickle django-celery


【解决方案1】:

context 字典中有一个对象,我不知道...

为了解决这个问题,我在异步调用之前执行了依赖于 context 的代码,并且只传递了一个只有本机类型的 dict:

def post_save(self, obj, created=False):
    context = self.get_serializer_context()
    clip_serializer = SolrClipSerializer(obj, context=context)
    update_solr.delay(clip_serializer.data)

任务最终是这样的:

@task
def update_solr(data):
    response = requests.post(url, data=data)

这非常好,因为使它成为异步任务的唯一目的是使 POST 非阻塞。

感谢您的帮助!

【讨论】:

    【解决方案2】:

    尝试传递模型实例主键 (pk)。这更容易腌制,减少负载并避免竞争条件。

    【讨论】:

    • 抱歉 - 以为您说它已修复 ;-) 您是否在没有 Celery 的情况下运行了该方法?
    【解决方案3】:
    import pickle
    class X:
        def y(self):
            pass
    
    pickle.dumps(X.y)
    

    Pickle 以递归方式工作,因此它可能位于对象图中的任何位置。您得到了解决方案 - 仅传输最小的对象,即主键等,而不是 Django 模型对象。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-09-06
      • 1970-01-01
      • 2011-07-18
      • 2011-07-17
      • 2011-11-22
      • 2012-02-11
      • 2016-08-13
      • 2021-02-25
      相关资源
      最近更新 更多