Почему автоопределение задач Celery никогда не срабатывает в Django?

У меня Celery 5.2.6 и Django 3.0.6. Все работает, кроме автообнаружения задач под Django.

Если я запускаю celery worker, рабочий запускает автообнаружение, находит все мои задачи и отображает их в списке как часть процесса запуска. Однако, если я запускаю свое Django приложение или Django shell, этого не происходит.

Далее, хотя в документации обещано, что обращение к реестру задач вызовет автообнаружение, этого не происходит. Я печатаю app.tasks, вызываю app.tasks.keys(), и все еще нет автообнаружения - он показывает только задачи, которые являются встроенными или были зарегистрированы, когда содержащий их модуль был импортирован по другим причинам.

Что нужно сделать для запуска автообнаружения задачи?

PS - Если я пытаюсь добавить force=True к app.autodiscover_tasks(), это не удается, потому что реестр приложений Django не закончил загрузку в это время.

Я покопался в коде и попробовал множество вещей. Вот что я узнал.

Как выполняется автообнаружение

Автопоиск фактически выполняется app._autodiscover_tasks() (src), который вызывается сигналом celery.signals.import_modules (src), посылаемым app.loader.import_default_modules() (src). Сигнал подключается к app._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

Если вы запускаете celery с командами beat, report, shell или worker, результирующий путь кода в конечном итоге вызывает app.loader.import_default_modules() напрямую. Таким образом, автообнаружение происходит в этих условиях - но не тогда, когда вы запускаете свое приложение Django, или открываете оболочку Django, или в любом другом контексте, кроме этих четырех команд, если вы явно не вызовете 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()
Вернуться на верх