ORM call in app.ready in ASGI mode

Hey, I’ve been experimenting with moving to hosting our moderately large Django installation into ASGI hosting mode, running on uvicorn. On a few of our projects everything seemed to be fine, but I have one where we have an issue with our setup. It appears that starting up in asgi mode, it doesn’t like the direct ORM call in our accounts app setup, where we ensure that one of our feature flags exists.

I’m not sure what the recommended way to do this is, or if there’s something obvious we’re doing wrong. The traceback we get on startup is below:

(apologies for image, the Stackdriver logs aren’t making it easy to export as text)

The asgi.py file looks like:

import os

from django.core.asgi import get_asgi_application

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "settings")
os.environ.setdefault("REQUESTS_CA_BUNDLE", "/etc/ssl/certs/ca-certificates.crt")
os.environ.setdefault(
    "NODE_PATH", "/usr/lib/nodejs:/usr/lib/node_modules:/usr/share/javascript"
)

application = get_asgi_application()

and the app.ready in question is:

from contextlib import suppress

from django.apps import AppConfig
from django.db import OperationalError
from django.db import ProgrammingError


class AccountsConfig(AppConfig):
    name = "accounts"

    def ready(self):
        from common.models import FeatureFlag

        with suppress(ProgrammingError, OperationalError):
            FeatureFlag.objects.get_or_create(
                name="SMS_SPECIFIC_TIME",
                defaults={
                    "enabled": True,
                    "description": "Send SMS at the time (24H) that is declared in data",  # noqa
                    "data": {"time": "20:00"},
                },
            )
        import accounts.signals  # noqa
        import accounts.messages  # noqa

Would greatly appreciate any advice on what we should be doing differently!

I feel like this likely counts as a bug, it’s quite common to use the ORM/DB in app.ready(). Django should run the ready() calls in sync mode. Probably worth a ticket.

Thanks for the reply! I’ve created the issue here https://code.djangoproject.com/ticket/31339

The documentation explicitly warns against performing queries during app.ready() so making Django call ready() in sync mode would encourage this pattern and all of its pitfalls.

I think it’s very unexpected that putting ORM calls here would work in WSGI mode and then stop working in ASGI mode. Given that I expect most people will continue to run WSGI mode for a long time, I can see this being a source of potential future headaches for a lot of people. Perhaps if calling the ORM in app.ready is not intended it should be entirely banned?

I think it’s very unexpected that putting ORM calls here would work in WSGI mode and then stop working in ASGI mode.

It’s only working because you are suppressing the exceptions (ProgrammingError, OperationalError) that are raised in WSGI mode.

You had to suppress these exceptions because if you make some schema changes to your FeatureFlag model or start from a new database it will even prevent you from calling any command, runserver, migrate, and makemigrations included.

I don’t see why you shouldn’t have to explicitly suppress SynchronousOnlyOperation as well if you want to swim against the current.

Perhaps if calling the ORM in app.ready is not intended it should be entirely banned?

Likely yes and it has already been discussed in on the mailing list.

1 Like

You’re right Simon. I was getting a bit mixed up between places queries can occur - we allow them in checks because some compare to the database.