代码之家  ›  专栏  ›  技术社区  ›  odigity

为什么在Django下Celery任务自动发现从未触发?

  •  0
  • odigity  · 技术社区  · 4 年前

    除了Django下的任务自动发现之外,一切都在工作。(芹菜5.2.6,Django 3.0.6)

    如果我跑步 celery worker ,worker触发自动发现,查找我的所有任务,并将它们显示在列表中,作为启动过程的一部分。然而,如果我运行我的Django应用程序或Django shell,这种情况永远不会发生。

    此外,即使 the docs promise 访问任务注册表将触发自动发现,但事实并非如此。我打印 app.tasks ,我打电话 app.tasks.keys() ,但仍然没有自动发现-它只显示内置的任务或在包含这些任务的模块由于其他原因被导入时注册的任务。

    我需要做什么才能触发任务自动发现?

    PS-如果我尝试添加 force=True 到 app.autodiscover_tasks() ,它失败了,因为Django应用程序注册表当时还没有完成加载。

    0 回复  |  直到 4 年前
        1
  •  -1
  •   odigity    4 年前

    我深入研究了代码并尝试了很多东西。以下是我学到的。

    如何执行自动发现

    自动发现实际上由执行 app._autodiscover_tasks() ( src ),由调用 celery.signals.import_modules 信号( src ),由发送 app.loader.import_default_modules() ( src )。信号连接到 应用程序_autodiscover_tasks() 在里面 app.autodiscover_tasks ( src )。

    换句话说,触发自动发现的唯一方法是:

    1. 呼叫 app.autodiscover_tasks() 注册 app._autodiscover_tasks 作为信号的接收器 celery.signals.import_modules
    2. 呼叫 app.loader.import_default_modules() 发送信号

    医生指示我做第一个,但不做第二个。因此,在我的Django应用程序中,自动发现是不会发生的。

    如何在中执行自动发现 celery

    如果你跑步 芹菜 使用命令 beat , report , shell 或 worker ,生成的代码路径最终调用 app.loader.import_default_modules() 直接地因此,自动发现是在这些条件下发生的,但不是在运行Django应用程序、打开Django shell或除这四个命令之外的任何其他上下文时,除非您显式调用 app.loader.import_default_modules() 。

    完成时

    文档承诺访问 app.tasks 将导致应用程序最终确定,我认为这会触发自动发现,但与此无关。所有这些 finalize 做的是发送 app.on_after_finalize 信号,它什么也不做。

    我的解决方案

    在经历了许多令人沮丧和实验之后,我决定从我的 celery.py :

    app = Celery("myproj")
    app.config_from_object("django.conf:settings", namespace="CELERY")
    app.autodiscover_tasks()
    
    @app.on_after_configure.connect()
    def trigger_autodiscovery(sender, **kwargs):
        app.loader.import_default_modules()
    
    推荐文章