Задать вопрос
@MaxIbragimov

Как корректно запустить SocketIO + Django?

Есть необходимость в проект на Django 4 добавить Socket.IO для ряда задач.

С помощью пакета python-socketio я её смог добавить. В качестве сервера используется настройка gunicorn + geventwebsocket.

Проведенные настройки:

# app/config/sockets.py
import socketio
from .settings import REDIS_HOST

from gevent import monkey
monkey.patch_all()

mgr = socketio.RedisManager(REDIS_HOST)
sio = socketio.Server(
    async_mode='gevent',
    client_manager=mgr,
    cors_allowed_origins="*",
    logger=True,
    engineio_logger=True,
    namespaces='*'
)


# app/config/wsgi.py

import os

from gevent import pywsgi
from geventwebsocket.handler import WebSocketHandler
from django.core.wsgi import get_wsgi_application
import socketio

from config.sockets import sio

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

application = get_wsgi_application()
application = socketio.WSGIApp(sio, application)
pywsgi.WSGIServer(('', 8800), application, handler_class=WebSocketHandler).serve_forever()


Запуск производится следующей командой:
gunicorn --reload -k geventwebsocket.gunicorn.workers.GeventWebSocketWorker -w 1 config.wsgi:application --bind 0.0.0.0:8000 --log-level debug


В итоге сокеты работают, а любой запрос по Rest API уходит в бесконечное ожидание. В логах сервиса только это:
[2023-03-14 12:17:48 +0000] [1] [INFO] Starting gunicorn 20.1.0                                                                                                                                                 
[2023-03-14 12:17:48 +0000] [1] [DEBUG] Arbiter booted                                                                                                                                                          
[2023-03-14 12:17:48 +0000] [1] [INFO] Listening at: http://0.0.0.0:8000 (1)                                                                                                                                    
[2023-03-14 12:17:48 +0000] [1] [INFO] Using worker: geventwebsocket.gunicorn.workers.GeventWebSocketWorker                                                                                                     
[2023-03-14 12:17:48 +0000] [24] [INFO] Booting worker with pid: 24                                                                                                                                             
[2023-03-14 12:17:48 +0000] [1] [DEBUG] 1 workers                                                                                                                                                               
Server initialized for gevent.                                                                                                                                                                                  
[2023-03-14 12:18:18 +0000] [1] [CRITICAL] WORKER TIMEOUT (pid:24)                                                                                                                                              
[2023-03-14 15:18:18 +0300] [24] [INFO] Worker exiting (pid: 24)                                                                                                                                                
[2023-03-14 12:18:18 +0000] [27] [INFO] Booting worker with pid: 27                                                                                                                                             
Server initialized for gevent.                                                                                                                                                                                  
[2023-03-14 12:18:48 +0000] [1] [CRITICAL] WORKER TIMEOUT (pid:27)
[2023-03-14 15:18:48 +0300] [27] [INFO] Worker exiting (pid: 27)
[2023-03-14 12:18:49 +0000] [30] [INFO] Booting worker with pid: 30
Server initialized for gevent.
[2023-03-14 12:19:19 +0000] [1] [CRITICAL] WORKER TIMEOUT (pid:30)
[2023-03-14 15:19:19 +0300] [30] [INFO] Worker exiting (pid: 30)
[2023-03-14 12:19:19 +0000] [33] [INFO] Booting worker with pid: 33
Server initialized for gevent.


В чем может быть причина? Правильно ли вообще настроил запуск? Или как-то надо разделить запуск веб-сервера для restapi и отдельно для сокетов?
  • Вопрос задан
  • 376 просмотров
Подписаться 1 Сложный 1 комментарий
Пригласить эксперта
Ответы на вопрос 1
The_Sketch
@The_Sketch
Веб разработчик x)
Проблема с тем, что запросы по Rest API уходят в бесконечное ожидание может быть вызвана таймаутом воркера.

Для устранения этой проблемы, можно увеличить таймаут воркера gunicorn до того времени, сколько он может выполнять запросы и ожидать ответы перед тем, как отвалиться.

Для этого нужно добавить следующий параметр к команде запуска gunicorn:
--timeout 600

Это установит таймаут в 600 секунд (10 минут).

Также, для предотвращения блокировки воркера gunicorn другими задачами, можно увеличить количество воркеров до нескольких.

Как пример, можно выполнить команду запуска gunicorn следующим образом:
gunicorn --workers 4 --timeout 600 --keep-alive 25 --reload -k geventwebsocket.gunicorn.workers.GeventWebSocketWorker -w 1 config.wsgi:application --bind 0.0.0.0:8000 --log-level debug

В этой команде были добавлены опции для увеличения количества воркеров (--workers), установки времени ожидания ответа сервера (--keep-alive) и повторного запуска воркера при изменении кода приложения (--reload).

Таким образом, после добавления этих настроек, воркеры gunicorn должны продолжать корректную работу с Socket.IO и Rest API.

Для сброса диалога введите команду /context

Jarvis IT Assistant, [14/03/23 18:53]
Сообщение "Server initialized for gevent" означает, что сервер успешно проинициализирован с использованием gevent - библиотеки для сетевого программирования событийного типа в Python.

Если вы запускаете как restapi, так и сокеты на одном и том же порту и в одном и том же процессе, то это может привести к ошибкам. Хотя Python может обрабатывать оба типа соединений, запуск веб-сервера для restapi и сокетов в одном процессе не является хорошей практикой.

Рекомендуется запускать сервер для restapi и сервер для сокетов в отдельных процессах, используя разные порты для каждого из них. Также вы можете использовать различные фреймворки для создания рест-интерфейса и работы с сокетами.

Если вы используете Flask, то вы можете использовать библиотеку Flask-SocketIO для работы с веб-сокетами. Эта библиотека позволяет запускать сервер для сокетов и сервер для rest api с использованием одного порта.

Независимо от того, как вы реализуете свой сервер, важно понимать, что правильная настройка и использование механизмов управления соединениями является важной частью разработки веб-приложений. Таким образом, следует уделять внимание этой теме, чтобы обеспечить эффективную работу веб-сервера и избежать возможных ошибок и проблем на этапе эксплуатации.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы