【问题标题】:Celery task best practices in Django/PythonDjango/Python 中的 Celery 任务最佳实践
【发布时间】:2014-08-03 13:25:15
【问题描述】:

考虑一个需要异步完成一些繁重工作的函数。调用客户端可以立即接收缓存版本,也可以接收正在处理数字的响应(客户端的有效响应)。

下面的 sn-p 是这种模式的合理实现吗?

from django.core import cache
from proj.celery import app

class SomeModel(models.Model):
    # ...
    def get_crunched_numbers(self):
        cache_key = 'foo:{}'.format(self.id)
        res = cache.get(cache_key)
        if not res:
            @app.task
            def gen_crunched_numbers():
                res = do_heavy_lifting()
                cache.set(cache_key, res)
                return res
            gen_crunched_numbers.delay()
            return 'crunching... come back later'
        else:
            return res

有没有更好的替代方案来运行像这样的 Celery 任务,同时将所有逻辑包含在单个代码中?

编辑:如 cmets 中所述,此代码甚至不起作用。所以任何关于一个好的模式的建议都是非常有义务的。

【问题讨论】:

  • 这真的有效吗?如果可以序列化这样的嵌套函数,我会感到惊讶。将cache_key 作为一个完全独立函数的参数肯定要好得多。
  • @DanielRoseman 你是对的,这只能在本地工作(使用ALWAYS_EAGER=True 时)并且完全不可序列化。

标签: python django celery


【解决方案1】:

您的代码看起来很混乱。你为什么不在你的类之外定义 celery 任务函数并像这样调用它:

from django.core import cache
from proj.celery import app

class SomeModel(models.Model):
    # ...
    def get_crunched_numbers(self):
        cache_key = 'foo:{}'.format(self.id)
        res = cache.get(cache_key)
        if not res:
            gen_crunched_numbers.delay(cache_key)
            return 'crunching... come back later'
        else:
            return res

@app.task
def gen_crunched_numbers(cache_key):
    res = do_heavy_lifting()
    cache.set(cache_key, res)
    return res

另外我通常更喜欢用bind=True创建任务:

@app.task(bind=True)
def gen_crunched_numbers(self, cache_key):
    res = do_heavy_lifting()
    cache.set(cache_key, res)
    return res

这使我可以通过self.request 访问task context。例如,根据函数是通过 celery 调用还是直接调用来改变行为:

@app.task(bind=True)
def gen_crunched_numbers(self, cache_key):
    res = do_heavy_lifting()
    cache.set(cache_key, res)
    if self.request.called_directly:
        return res
    else:
        return { 'result': res, 'cache': cache_key }

【讨论】:

  • 我试图将所有逻辑封装在一个函数中,但正如您所见,它并没有真正起作用。您的建议看起来不错,这就是我目前正在使用的。 bind=True 是一个非常好的改进,我也可能会使用它。谢谢!
猜你喜欢
  • 2011-11-21
  • 2020-09-02
  • 2012-11-02
  • 2021-05-23
  • 2016-06-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多