Почему автоопределение задач 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).
Другими словами, единственный способ заставить автообнаружение сработать - это:
- вызов
app.autodiscover_tasks()для регистрацииapp._autodiscover_tasksв качестве приемника сигналаcelery.signals.import_modules - вызовите
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()