0
votes

I'm trying to integrate Celery into my Django project. I've followed the Celery docs, and I can execute a simple Hello World task. But when I try to import my models into my task definitions, I am getting the AppRegisteredNotReady exception. I'm finding some older discussions around this exception, but nothing current. I'm probably missing something quite simple.

Python 3.5, Django 1.9, Celery 3.1.23

Celery.py:

from __future__ import absolute_import
import os
from celery import Celery
from django.conf import settings

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings.local')  # pragma: no cover

app = Celery('autopool')
app.config_from_object('django.conf:settings')
app.autodiscover_tasks(lambda: settings.INSTALLED_APPS, force=True)

@app.task(bind=True)
def debug_task(self):
    print('Request: {0!r}'.format(self.request))  # pragma: no cover

autopool/init.py:

from __future__ import absolute_import

from autopool.celery import app as celery_app  # noqa

apps/pools/tasks.py:

from __future__ import absolute_import
from celery import shared_task

@shared_task
def send_period_mail(period_id):
    print("Mail sent for period " + period_id)

I start Celery with the command:

celery -A autopool worker -l info

From my view, I execute:

import .tasks send_period_mail
send_period_mail(period_id=period.id)

This all works.

However when I try to add a model to the task:

from __future__ import absolute_import
from celery import shared_task
from .models import Period

@shared_task
def send_period_mail(period_id):
    print("Mail sent for period " + period_id)

Now when I try to start celery, I receive the AppRegisteryNotReady: Apps aren't loaded yet exception.

Full stack trace: http://pastebin.com/kmJZLHpT

Anyone have a clue?

2

2 Answers

0
votes

Because when the celery.py file is imported Django haven't loaded the apps/models yet (so it fails to import the model from .models import Period) move the import inside the function

@shared_task
def send_period_mail(period_id):
    from .models import Period
    print("Mail sent for period " + period_id)

so it will only be loaded when the function is called (and Django is ready)

0
votes

Marco's answer works. Thanks, Marco.

I also discovered that I could fix it by removing the force=True from the autodiscover_tasks() setting.

Change app.autodiscover_tasks(lambda: settings.INSTALLED_APPS, force=True) to app.autodiscover_tasks(lambda: settings.INSTALLED_APPS)