如何将带有通道和 websocket 的 django 应用程序部署到 Heroku?

How to deploy django app with channels and websocket to Heroku?

我正在创建 Messanger。我遇到了将我的应用程序部署到 heroku 的需求。

我的config/settings.py

from pathlib import Path
from datetime import timedelta
import os

BASE_DIR = Path(__file__).resolve().parent.parent

SECRET_KEY = os.environ.get('SECRET_KEY')

DEBUG = True

ALLOWED_HOSTS = ['*']

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'rest_framework',
    'rest_framework_simplejwt',
    'corsheaders',
    'users',
    'tokens',
    'channels',
    'chat',
    'college'
]

AUTH_USER_MODEL = 'users.User'

ASGI_APPLICATION = 'config.asgi.application'

CHANNEL_LAYERS = {
    'default': {
        'BACKEND': 'channels_redis.core.RedisChannelLayer',
        'CONFIG': {
            "hosts": [(os.environ.get('REDIS_URI'), 25690)],
        },
    },
}

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

WSGI_APPLICATION = 'config.wsgi.application'

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': os.environ.get('ELEPHANT_NAME'),
        'USER': os.environ.get('ELEPHANT_USER'),
        'PASSWORD': os.environ.get('ELEPHANT_PASSWORD'),
        'HOST': os.environ.get('ELEPHANT_HOST'),
        'PORT': 5432
    }
}


STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'static')

MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
........................

我使用 heroku-redis

config.asgi

import os

from channels.routing import ProtocolTypeRouter, URLRouter
from django.core.asgi import get_asgi_application
import chat.routing

from config.middlewares import TokenAuthMiddleware

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings")

application = ProtocolTypeRouter({
  "http": get_asgi_application(),
  "websocket": TokenAuthMiddleware(
        URLRouter(
            chat.routing.websocket_urlpatterns
        )
    ),
})

过程文件

release: python manage.py migrate
web: daphne config.asgi:application --port $PORT --bind 0.0.0.0 -v2
worker: python manage.py runworker channels --settings=core.settings -v2

老实说,我不知道应该指定哪个端口。觉得不重要所以离开了8001

requirements.txt

....................
daphne==3.0.2
Django==3.2.9
gunicorn==20.1.0
hiredis==2.0.0
psycopg2==2.9.2
channels==3.0.4
channels-redis==3.3.1
.....................

我收到错误

2021-12-24T13:28:26.164337+00:00 heroku[web.1]: State changed from crashed to starting
2021-12-24T13:28:31.530462+00:00 heroku[web.1]: Starting process with command `daphne config.asgi:application --port 59828 --bind 0.0.0.0 -v2`
2021-12-24T13:28:33.068963+00:00 app[web.1]: Traceback (most recent call last):
2021-12-24T13:28:33.068982+00:00 app[web.1]: File "/app/.heroku/python/bin/daphne", line 8, in <module>
2021-12-24T13:28:33.069042+00:00 app[web.1]: sys.exit(CommandLineInterface.entrypoint())
2021-12-24T13:28:33.069044+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.9/site-packages/daphne/cli.py", line 170, in entrypoint
2021-12-24T13:28:33.069151+00:00 app[web.1]: cls().run(sys.argv[1:])
2021-12-24T13:28:33.069160+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.9/site-packages/daphne/cli.py", line 232, in run
2021-12-24T13:28:33.069237+00:00 app[web.1]: application = import_by_path(args.application)
2021-12-24T13:28:33.069247+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.9/site-packages/daphne/utils.py", line 12, in import_by_path
2021-12-24T13:28:33.069292+00:00 app[web.1]: target = importlib.import_module(module_path)
2021-12-24T13:28:33.069294+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.9/importlib/__init__.py", line 127, in import_module
2021-12-24T13:28:33.069356+00:00 app[web.1]: return _bootstrap._gcd_import(name[level:], package, level)
2021-12-24T13:28:33.069364+00:00 app[web.1]: File "<frozen importlib._bootstrap>", line 1030, in _gcd_import
2021-12-24T13:28:33.069433+00:00 app[web.1]: File "<frozen importlib._bootstrap>", line 1007, in _find_and_load
2021-12-24T13:28:33.069471+00:00 app[web.1]: File "<frozen importlib._bootstrap>", line 986, in _find_and_load_unlocked
2021-12-24T13:28:33.069568+00:00 app[web.1]: File "<frozen importlib._bootstrap>", line 680, in _load_unlocked
2021-12-24T13:28:33.069569+00:00 app[web.1]: File "<frozen importlib._bootstrap_external>", line 850, in exec_module
2021-12-24T13:28:33.069590+00:00 app[web.1]: File "<frozen importlib._bootstrap>", line 228, in _call_with_frames_removed
2021-12-24T13:28:33.069628+00:00 app[web.1]: File "/app/./config/asgi.py", line 6, in <module>
2021-12-24T13:28:33.069680+00:00 app[web.1]: import chat.routing
2021-12-24T13:28:33.069681+00:00 app[web.1]: File "/app/./chat/routing.py", line 3, in <module>
2021-12-24T13:28:33.069727+00:00 app[web.1]: from . import consumers
2021-12-24T13:28:33.069735+00:00 app[web.1]: File "/app/./chat/consumers.py", line 4, in <module>
2021-12-24T13:28:33.069777+00:00 app[web.1]: from .models import Message, Chat, File
2021-12-24T13:28:33.069785+00:00 app[web.1]: File "/app/./chat/models.py", line 3, in <module>
2021-12-24T13:28:33.069827+00:00 app[web.1]: from users.models import User
2021-12-24T13:28:33.069834+00:00 app[web.1]: File "/app/./users/models.py", line 3, in <module>
2021-12-24T13:28:33.069877+00:00 app[web.1]: from django.contrib.auth.models import AbstractUser, Group
2021-12-24T13:28:33.069885+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.9/site-packages/django/contrib/auth/models.py", line 3, in <module>
2021-12-24T13:28:33.069930+00:00 app[web.1]: from django.contrib.auth.base_user import AbstractBaseUser, BaseUserManager
2021-12-24T13:28:33.069938+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.9/site-packages/django/contrib/auth/base_user.py", line 48, in <module>
2021-12-24T13:28:33.069991+00:00 app[web.1]: class AbstractBaseUser(models.Model):
2021-12-24T13:28:33.069997+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.9/site-packages/django/db/models/base.py", line 108, in __new__
2021-12-24T13:28:33.070056+00:00 app[web.1]: app_config = apps.get_containing_app_config(module)
2021-12-24T13:28:33.070064+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.9/site-packages/django/apps/registry.py", line 253, in get_containing_app_config
2021-12-24T13:28:33.070148+00:00 app[web.1]: self.check_apps_ready()
2021-12-24T13:28:33.070156+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.9/site-packages/django/apps/registry.py", line 136, in check_apps_ready
2021-12-24T13:28:33.070219+00:00 app[web.1]: raise AppRegistryNotReady("Apps aren't loaded yet.")
2021-12-24T13:28:33.070242+00:00 app[web.1]: django.core.exceptions.AppRegistryNotReady: Apps aren't loaded yet.
2021-12-24T13:28:33.285009+00:00 heroku[web.1]: Process exited with status 1

我该如何解决这个问题?如果你需要我给你看的其他东西,请评论

您需要在导入任何模型之前调用 get_asgi_applicationimport chat.routing 似乎会触发模型导入,因此在此导入之前调用 get_asgi_application()

config.asgi

import os

from channels.routing import ProtocolTypeRouter, URLRouter
from django.core.asgi import get_asgi_application

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings")
django_asgi_app = get_asgi_application()

import chat.routing

from config.middlewares import TokenAuthMiddleware

application = ProtocolTypeRouter({
  "http": django_asgi_app,
  "websocket": TokenAuthMiddleware(
        URLRouter(
            chat.routing.websocket_urlpatterns
        )
    ),
})