Heroku部署Django/Channels(ASGI)应用时出现AppRegistryNotReady错误
在Heroku部署集成Channels的Django ASGI应用时遇到AppRegistryNotReady错误
问题描述
本地运行正常,但部署到Heroku后启动失败,出现AppRegistryNotReady: Apps aren't loaded yet.错误,相关日志及配置如下:
Heroku日志
2023-09-29T13:50:20.958856+00:00 heroku[web.1]: State changed from crashed to starting 2023-09-29T13:50:24.630050+00:00 heroku[web.1]: Starting process with command `daphne nanochat.asgi:application --port 16299 --bind 0.0.0.0 -v2` 2023-09-29T13:50:25.627718+00:00 app[web.1]: Traceback (most recent call last): 2023-09-29T13:50:25.627755+00:00 app[web.1]: File "/app/.heroku/python/bin/daphne", line 8, in <module> 2023-09-29T13:50:25.627769+00:00 app[web.1]: sys.exit(CommandLineInterface.entrypoint()) 2023-09-29T13:50:25.627785+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.10/site-packages/daphne/cli.py", line 171, in entrypoint 2023-09-29T13:50:25.627826+00:00 app[web.1]: cls().run(sys.argv[1:]) 2023-09-29T13:50:25.627827+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.10/site-packages/daphne/cli.py", line 233, in run 2023-09-29T13:50:25.627875+00:00 app[web.1]: application = import_by_path(args.application) 2023-09-29T13:50:25.627876+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.10/site-packages/daphne/utils.py", line 12, in import_by_path 2023-09-29T13:50:25.627909+00:00 app[web.1]: target = importlib.import_module(module_path) 2023-09-29T13:50:25.627909+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.10/importlib/__init__.py", line 126, in import_module 2023-09-29T13:50:25.627951+00:00 app[web.1]: return _bootstrap._gcd_import(name[level:], package, level) 2023-09-29T13:50:25.627952+00:00 app[web.1]: File "<frozen importlib._bootstrap>", line 1050, in _gcd_import 2023-09-29T13:50:25.628008+00:00 app[web.1]: File "<frozen importlib._bootstrap>", line 1027, in _find_and_load 2023-09-29T13:50:25.628030+00:00 app[web.1]: File "<frozen importlib._bootstrap>", line 1006, in _find_and_load_unlocked 2023-09-29T13:50:25.628055+00:00 app[web.1]: File "<frozen importlib._bootstrap>", line 688, in _load_unlocked 2023-09-29T13:50:25.628081+00:00 app[web.1]: File "<frozen importlib._bootstrap_external>", line 883, in exec_module 2023-09-29T13:50:25.628117+00:00 app[web.1]: File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed 2023-09-29T13:50:25.628142+00:00 app[web.1]: File "/app/./nanochat/asgi.py", line 16, in <module> 2023-09-29T13:50:25.628169+00:00 app[web.1]: import chat.routing 2023-09-29T13:50:25.628170+00:00 app[web.1]: File "/app/./chat/routing.py", line 3, in <module> 2023-09-29T13:50:25.628195+00:00 app[web.1]: from . import consumers 2023-09-29T13:50:25.628196+00:00 app[web.1]: File "/app/./chat/consumers.py", line 5, in <module> 2023-09-29T13:50:25.628223+00:00 app[web.1]: from .models import Conversation, Message 2023-09-29T13:50:25.628223+00:00 app[web.1]: File "/app/./chat/models.py", line 5, in <module> 2023-09-29T13:50:25.628251+00:00 app[web.1]: from base.models import Company, Customer 2023-09-29T13:50:25.628251+00:00 app[web.1]: File "/app/./base/models.py", line 5, in <module> 2023-09-29T13:50:25.628278+00:00 app[web.1]: class Company(models.Model): 2023-09-29T13:50:25.628278+00:00 app[web.1]: File "/app/./base/models.py", line 20, in Company 2023-09-29T13:50:25.628333+00:00 app[web.1]: staff = models.ManyToManyField(get_user_model(), through='Role') 2023-09-29T13:50:25.628334+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.10/site-packages/django/contrib/auth/__init__.py", line 170, in get_user_model 2023-09-29T13:50:25.628356+00:00 app[web.1]: return django_apps.get_model(settings.AUTH_USER_MODEL, require_ready=False) 2023-09-29T13:50:25.628357+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.10/site-packages/django/apps/registry.py", line 203, in get_model 2023-09-29T13:50:25.628398+00:00 app[web.1]: self.check_apps_ready() 2023-09-29T13:50:25.628398+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.10/site-packages/django/apps/registry.py", line 138, in check_apps_ready 2023-09-29T13:50:25.628431+00:00 app[web.1]: raise AppRegistryNotReady("Apps aren't loaded yet.") 2023-09-29T13:50:25.628449+00:00 app[web.1]: django.core.exceptions.AppRegistryNotReady: Apps aren't loaded yet. 2023-09-29T13:50:25.808196+00:00 heroku[web.1]: Process exited with status 1 2023-09-29T13:50:25.838513+00:00 heroku[web.1]: State changed from starting to crashed
配置文件
asgi.py
import os from channels.routing import ProtocolTypeRouter, URLRouter from django.core.asgi import get_asgi_application import chat.routing os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'nanochat.settings') django_asgi_app = get_asgi_application() application = ProtocolTypeRouter({ "http": get_asgi_application(), "websocket": URLRouter( chat.routing.websocket_urlpatterns ), })
settings.py
INSTALLED_APPS = [ 'daphne', 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'base', 'accounts', 'payment', 'common', 'utils', 'notification', 'rest_framework', 'rest_framework_simplejwt', # 'drf_spectacular', 'channels', 'drf_yasg', 'corsheaders', 'push_notifications', 'chat', 'django.contrib.staticfiles', ] ASGI_APPLICATION = "nanochat.asgi.application" CHANNEL_LAYERS = { 'default': { 'BACKEND': "channels.layers.InMemoryChannelLayer" } }
Procfile
release: python manage.py migrate web: daphne nanochat.asgi:application --port $PORT --bind 0.0.0.0 -v2
成因分析
从日志调用链可以看出,import chat.routing语句在Django应用初始化(get_asgi_application())之前就触发了模型导入——这个导入会递归加载消费者、模型文件,而此时Django的App Registry还未完成初始化,导致调用get_user_model()时抛出错误。
本地运行正常是因为本地环境可能通过启动命令(如runserver)提前完成了Django配置加载,掩盖了导入顺序问题,但Heroku生产环境下Daphne直接加载ASGI应用时,这个顺序问题就会暴露。
解决方案
调整ASGI文件的导入顺序,将路由导入移到Django应用初始化完成之后:
修改后的asgi.py:
import os from channels.routing import ProtocolTypeRouter, URLRouter from django.core.asgi import get_asgi_application os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'nanochat.settings') # 先完成Django应用初始化 django_asgi_app = get_asgi_application() # 此时App Registry已加载,再导入路由 import chat.routing application = ProtocolTypeRouter({ "http": django_asgi_app, # 复用已初始化的应用实例,避免重复初始化 "websocket": URLRouter( chat.routing.websocket_urlpatterns ), })
额外优化建议
- 检查消费者文件,若模块级别直接导入模型,可将导入移到函数内部(比如
connect方法里),避免模块加载时触发模型初始化。 - 确认
requirements.txt中包含daphne和channels,确保Heroku能正确安装依赖。
内容的提问来源于stack exchange,提问作者Evans
相关产品推荐
相关产品推荐

