Странное поведение с django и websocket за nginx

У меня есть приложение Docker Django, которое использует каналы django и Redis для потоковой передачи данных. Все это находится за Nginx. Все работает, кажется, хорошо. Я могу обращаться к своим сайтам под поддоменами, а также могу подключаться через websocket.

Единственная проблема заключается в том, что вебсокет передает данные, и каждый короткий промежуток времени (несколько секунд) он блокируется почти ровно на 5 секунд, а затем продолжает передачу... Как если бы каждый короткий промежуток времени запускалась фоновая задача, которая блокирует мой код. В логах я не вижу никакой ошибки. Также значения, которые я получаю на стороне клиента, иногда дублируются, а иногда и не совпадают...

Я выложил свой код. Надеюсь, это не слишком много...

У меня есть тестовый поток в django, отправляющий тестовые данные:

# websocket/apps.py
from django.apps import AppConfig
from threading import Thread
from channels.layers import get_channel_layer
from asgiref.sync import async_to_sync

def task_handler():

    count = 0
    
    run = True
    while run:

        channel_layer = get_channel_layer() #  <-- THIS BLOCKS SOMETIMES FOR 5 SECONDS

        async_to_sync(channel_layer.group_send)('group_1', {'type': 'send_message', 'message': str({'c': count})})

        count+=1
        time.sleep(0.1)


class WebsocketConfig(AppConfig):
    default_auto_field = 'django.db.models.BigAutoField'
    name = 'websocket'

    def ready(self) -> None:
        Thread(target=task_handler, daemon=True).start()

Это мой файл asgi.py:

# asgi.py
import os
from channels.auth import AuthMiddlewareStack
from channels.routing import ProtocolTypeRouter, URLRouter
from django.core.asgi import get_asgi_application
import websocket.routing


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

application = ProtocolTypeRouter({
    "http": get_asgi_application(),
    # Just HTTP for now. (We can add other protocols later.)
    "websocket": AuthMiddlewareStack(
                URLRouter(
                    websocket.routing.websocket_urlpatterns
                )
            )
    })

файл my consumers.py:

# websocket/consumers.py
import json
from channels.generic.websocket import AsyncWebsocketConsumer


class DataConsumer(AsyncWebsocketConsumer):
    async def connect(self):
        # Join room group
        await self.channel_layer.group_add(
            'group_1',
            self.channel_name
        )

        await self.accept()

    async def disconnect(self, close_code):
        # Leave room group
        await self.channel_layer.group_discard(
            'group_1',
            self.channel_name
        )

    # Receive message from WebSocket
    async def receive(self, text_data):
        text_data_json = json.loads(text_data)
        message = text_data_json['message']

        # Send message to room group
        await self.channel_layer.group_send(
            'group_1',
            {
                'type': 'chat_message',
                'message': message
            }
        )

    # Receive message from room group
    async def send_message(self, event):
        message = event['message']

        # Send message to WebSocket
        await self.send(text_data=json.dumps({
            'message': message
        }))

Мой файл routing.py:

# websocket/routing.py
from django.urls import path
from .consumers import DataConsumer

websocket_urlpatterns = [
    path('ws/data/', DataConsumer.as_asgi()),
]

мой файл docker-compose.yml:

version: "3.8"
services:  
  nginx-proxy:
    image: jwilder/nginx-proxy
    ports:
      - "80:80"
    volumes:
      - /var/run/docker.sock:/tmp/docker.sock
      - ./system_files/nginx/templates:/app/templates
      - ./system_files/nginx/nginx.conf:/etc/nginx/nginx.conf
      - ./system_files/nginx/conf.d:/etc/nginx/conf.d
    networks:
    - backend
    - frontend
  db:
    image: postgres
    volumes:
      - ./data/db:/var/lib/postgresql/data
    environment:
      - POSTGRES_DB=postgres
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=postgres
    networks:
    - backend
  app:
    build: .
    volumes:
      - .:/app_test
    restart: always
    environment:
    - VIRTUAL_HOST=iot.localhost
    - VIRTUAL_PORT=8000
    - POSTGRES_NAME=postgres
    - POSTGRES_USER=postgres
    - POSTGRES_PASSWORD=postgres
    command: bash -c "sleep 5 && python3 manage.py runserver 0.0.0.0:8000"
    depends_on:
    - db
    - nginx-proxy
    networks:
    - backend
    - frontend
  redis:
    image: redis:alpine
    ports:
    - 6379:6379
    depends_on:
    - db
    - app
    restart: always
    networks:
    - backend
    - frontend
networks:
  frontend:
    name: frontend-network
  backend:
    name: backend-network
  mqtt:
    name: mqtt-network

и мой файл конфигурации nginx:

Добавьте на стороне клиента мой тестовый скрипт:

<script>

    var w_url = 'ws://'+window.location.host+'/ws/data/';

    console.log(w_url);
    const mapSocket = new WebSocket(w_url);

    mapSocket.onmessage = function(e) {
        const data = JSON.parse(e.data);
        console.log(data.message);
    };
    mapSocket.onclose = function(e) {
        console.error('socket closed unexpectedly');
    };

</script>

Как вы можете видеть в консоли на стороне клиента, я получаю сообщения не в порядке отправки, а иногда они повторяются и через несколько секунд после отправки. enter image description here

Вернуться на верх