docker-compose中的websockets with Django channels rest框架

w7t8yxp5  于 2023-03-29  发布在  Docker
关注(0)|答案(1)|浏览(125)

我使用Django channels rest framework创建了一个带有两个websockets连接的应用程序。在本地,一切正常。我有这样的设置:

#routing.py
from channels.auth import AuthMiddlewareStack
from channels.routing import ProtocolTypeRouter, URLRouter
from django.core.asgi import get_asgi_application
from django.urls import re_path
from gnss.consumers import CoordinateConsumer  # noqa
from operations.consumers import OperationConsumer  # noqa

websocket_urlpatterns = [
    re_path(r'ws/coordinates/', CoordinateConsumer.as_asgi()),
    re_path(r'ws/operations/', OperationConsumer.as_asgi()),
]

application = ProtocolTypeRouter({
    'http': get_asgi_application(),
    'websocket': AuthMiddlewareStack(
        URLRouter(websocket_urlpatterns)
    ),
})

# consumers.py
from djangochannelsrestframework.decorators import action  # noqa
from djangochannelsrestframework.generics import GenericAsyncAPIConsumer  # noqa
from djangochannelsrestframework.observer import model_observer  # noqa
from djangochannelsrestframework.observer.generics import action  # noqa
from djangochannelsrestframework.permissions import AllowAny  # noqa

from .models import Coordinate
from .serializers import CoordinateSerializer

class CoordinateConsumer(GenericAsyncAPIConsumer):
    queryset = Coordinate.objects.all()
    serializer_class = CoordinateSerializer
    permission_classes = (AllowAny,)

    @model_observer(Coordinate)
    async def coordinates_activity(self, message, action=None, **kwargs):
        await self.send_json(message)

    @coordinates_activity.serializer
    def coordinates_activity(self, instance: Coordinate, action, **kwargs):
        return dict(CoordinateSerializer(instance).data,
                    action=action.value, pk=instance.pk)

    @action()
    async def subscribe_to_coordinates_activity(self, request_id, **kwargs):
        await self.coordinates_activity.subscribe(request_id=request_id)

至于consumers.py的**ws/operations/**也是一样的。当我在开发服务器(python www.example.com runserver)的本地机器上运行我的Django应用程序时manage.py,一切都很好。但是由于某种原因,当我在docker-compose中运行我的应用程序时,ws/operations/工作,但ws/coordinates不工作。由于某种原因,我没有收到来自Django的消息。
我的 composer

version: "3.7"

x-api-common: &api
  build: ./backend
  restart: always
  env_file: ./config/api/.env
  volumes:
    - ./backend/api:/opt/code
    - static_volume:/home/app/web/staticfiles
    - media_volume:/home/app/web/media
  networks:
    - nginx_network
    - postgres_network
  depends_on:
    - redis
    - postgres

services:

  wsgi:
    <<: *api
    command: "bash /opt/code/docker-wsgi-entrypoint.sh"
    container_name: operations_wsgi
    environment:
      is_wsgi: 'true'
    ports:
      - 8000:8000

  asgi:
    <<: *api
    command: "bash /opt/code/docker-asgi-entrypoint.sh"
    container_name: operations_asgi
    ports:
      - 8001:8001
    depends_on:
      - wsgi

  admin:
    <<: *api
    container_name: operations_admin
    ports:
      - 8002:8002
    depends_on:
      - wsgi
    command: gunicorn api.wsgi:application --bind 0.0.0.0:8002 --workers 2 --timeout 600

  web:
    build:
      context: ./frontend
      dockerfile: Dockerfile
    restart: "on-failure"
    ports:
      - 80:80
    volumes:
      - ./frontend:/app
      - '/app/node_modules'
      - static_volume:/home/app/web/staticfiles
      - media_volume:/home/app/web/media
    depends_on:
      - wsgi
      - asgi
      - admin
    networks:
      - nginx_network

  redis:
    image: "redis:6.2.7-alpine"
    restart: always
    command:
      - /bin/sh
      - -c
      - redis-server --requirepass "$${REDIS_PASSWORD:?REDIS_PASSWORD variable is not set}"
    ports:
      - "6379:6379"
    env_file:
      - ./config/redis/.env
    networks:
      - nginx_network

  postgres:
    image: postgres:13.0
    restart: always
    ports:
      - 5432:5432
    env_file: config/postgres/.env
    networks:
      - postgres_network
    volumes:
      - ./data/postgres-data:/var/lib/postgresql/data

  rabbitmq:
    image: 'rabbitmq:3.6-management-alpine'
    restart: always
    ports:
      - '5672:5672'
      - '15672:15672'
    env_file: config/rabbitmq/.env

networks:
  nginx_network:
    driver: bridge
  postgres_network:
    driver: bridge

volumes:
  static_volume:
  media_volume:

我的nginx配置

upstream wsgi_server {
    server wsgi:8000;
}

upstream asgi_server {
    server asgi:8001;
}

upstream admin_server {
    server admin:8002;
}

server {

  listen 80;
  server_name localhost;
  charset utf-8;
  server_tokens off;
  client_max_body_size 20M;
  resolver 10.0.0.2 valid=300s;
  resolver_timeout 10s;

    location ~* ^/ws/ {
      proxy_pass http://asgi_server;
      proxy_set_header Upgrade $http_upgrade;
      proxy_set_header Connection "Upgrade";
      proxy_set_header Host            $host;
      proxy_set_header X-Forwarded-For $remote_addr;
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Scheme $scheme;
      proxy_set_header REMOTE_ADDR $remote_addr;
    }

    location ~ ^/static/(?<base_path>rest_framework|admin|drf-yasg)/(?<tail>.*)$ {
        autoindex on;
        alias /home/app/web/staticfiles/$base_path/$tail;
    }

    location ~ ^/media/(?<base_path>images)/(?<tail>.*)$ {
        autoindex on;
        alias /home/app/web/media/$base_path/$tail;
        add_header Content-disposition "attachment";
    }

    location ~ ^/api|swagger|redoc/ {
        proxy_pass http://wsgi_server;
        proxy_pass_request_headers on;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_redirect off;
    }

    location ~ ^/admin/ {
        proxy_pass http://admin_server;
        proxy_pass_request_headers on;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_redirect off;
    }

    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
        try_files $uri $uri/ /index.html;
    }

  error_page   500 502 503 504  /50x.html;

  location = /50x.html {
    root   /usr/share/nginx/html;
  }
}

我不知道这是怎么了

dgtucam1

dgtucam11#

要解决此问题,请执行以下操作:
1.将def ready()函数添加到apps.py,如下所示:

from django.apps import AppConfig

class GnssConfig(AppConfig):
    name = 'gnss'
    verbose_name = 'GNSS management'

    def ready(self) -> None:
        from .consumers import CoordinateConsumer  # noqa

1.这样配置nginx:

location ~ ^/ws/operations|coordinates/ {
      proxy_pass http://asgi_server;
      proxy_http_version 1.1;
      proxy_set_header Upgrade $http_upgrade;
      proxy_set_header Connection "upgrade";
    }

这是两个endpoints ws/operations和ws/coordinates的示例

相关问题