Обновление в реальном времени приложения Django с использованием MySQL <> WebSocket - PullRequest
3 голосов
/ 07 августа 2020

Мне нужно постоянно получать данные из базы данных MySQL, которая получает данные с частотой обновления около 200 мс. Мне нужно постоянно обновлять значение данных в текстовом поле приборной панели. Моя приборная панель построена на Django.

Я много читал о Channels, но все руководства посвящены приложениям чата. Я знаю, что мне нужно реализовать WebSockets, который будет иметь открытое соединение и получать данные. С приложением чата это имеет смысл, но я не встречал ничего, что говорило бы о базе данных MySQL.

Я также читал о mysql-events. Поскольку данные, которые поступают в таблицу, поступают от внешнего датчика, я не понимаю, как я могу контролировать таблицу внутри Django, т.е. всякий раз, когда в таблицу добавляется новая строка, мне нужно, чтобы эта новая вставлялась на основе значение столбца.

Есть идеи, как go об этом? Я просмотрел много статей и не смог найти что-нибудь, c отвечающее этому требованию.

1 Ответ

1 голос
/ 30 августа 2020

Лучше всего, если вам нужно постоянно запрашивать базу данных sql, было бы использовать Celery или dramatiq, что проще / проще, но менее проверено в боях в сочетании с Django Channels.

Celery позволяет вам для создания рабочих (вроде фоновых процессов), которым вы можете отправлять задачи (функции). Когда рабочий получает задачу, она будет выполнена. Все это делается в фоновом режиме. Из задачи, которую выполняет воркер, вы можете отправлять данные обратно через веб-сокет прямо из воркера. Это работает, только если у вас включены django каналов + слои каналов, потому что, когда вы включаете слои каналов, каждый экземпляр потребителя, созданный при открытии канала / веб-сокета, будет иметь имя, которое вы можете передать работнику, чтобы он знал, какой веб-сокет использовать отправить данные запроса обратно в.

Вот как будет выглядеть поток этого процесса:

  1. Клиентские запросы на подключение к вашему веб-сокету
  2. Экземпляр-потребитель создан и с ним задано c имя для него
  3. Экземпляр-потребитель принимает соединение
  4. Потребитель запускает задачу сельдерея и передает имя
  5. Рабочий начинает опрос ваших SQL баз данных каждые X секунд
  6. Когда работник находит новую запись, используйте присвоенное ему имя и отправьте новую запись обратно через веб-узел.

Я предлагаю прочитать документацию по каналам django для потребителей и слои каналов, а также уроки сельдерея или драматика, чтобы понять, как они работают. Чтобы все это работало, вам также нужно будет узнать о Redis и службе очереди сообщений, такой как RabbitMQ. Слишком много для простого ответа, но я могу предоставить дополнительную информацию, если у вас есть конкретные c вопросы.

Изменить:

  • Установите Redis Server Setup на свой компьютер. Если вы используете Windows, как и я, вам необходимо загрузить WSL 2 и установить Ubuntu из Windows Store (бесплатно). Эта ссылка поможет вам пройти через него.

  • Получить настройку сервера RabbitMQ. Следуйте их руководству

  • Включите Django Каналы и Django -Channel-Layers, а затем установите Redis по умолчанию Django -канальный сервер .

  • Настройка Dramatiq или Celery. Я предпочитаю Dramatiq, поскольку это в основном новая и улучшенная версия Celery, хотя и менее популярная. Его намного проще настроить и использовать. Этот является репозиторием на github для Django -dramatiq, и он расскажет, как его настроить. Обратите внимание, что точно так же, как при запуске сервера django с python manage.py runserver, перед тестированием веб-сайта вам необходимо запустить работников dramatiq с python manage.py rundramatiq.

  • Создайте файл tasks.py в ваше приложение django и внутри этой задачи реализуйте свой код для проверки базы данных MySQL на наличие новых записей. Если вы еще этого не поняли, вот ссылка , чтобы начать с этого. В файле задач у вас должна быть функция с декоратором dramatiq.actor наверху, чтобы dramatiq знал, что функция является задачей.

  • Создайте потребителя django каналов для обработки Соединения WebSocket, а также позволяют отправлять данные через соединение WebSocket. Вот как будет выглядеть стандартный потребитель:

class AsyncDashboardConsumer(AsyncJsonWebsocketConsumer):

    async def connect(self):
        await self.accept()

    async def disconnect(self, code):
        await self.close()

    async def receive_json(self, text_data=None, bytes_data=None, **kwargs):
        someData = text_data['someData']
        someOtherData = text_data['someOtherData']

        if 'execute_getMySQLdata' in text_data['function']:
            await self.getData(someData, someOtherData)

    async def sendDataToClient(self, event):
        await self.send(text_data=event['text'])

    async def getData(self, someData, someOtherData):
        sync_to_async(SQLData.send(self.channel_name, someData, someOtherData))
  • connect функция вызывается, когда клиент пытается подключиться к URL-адресу WebSocket, который ваш маршрутизатор файл (на шаге 2) указывает на этого потребителя.

  • recieve_json функция вызывается всякий раз, когда клиент отправляет данные на ваш django сервер.

  • Функция

    getData вызывается из функции recieve_json и отправляет сообщение для запуска вашей задачи dramatiq, которую вы создали ранее для проверки SQL db. Обратите внимание, что при отправке сообщения вы должны передать self.channel_name, поскольку вы используете это имя_канала для отправки данных обратно через WebSocket непосредственно из рабочего / задания dramatiq.

  • sendDataToClient function используется, когда вы отправляете данные обратно клиенту. Итак, когда вы отправляете данные из своей задачи, это функция, которую вы должны передать как вызываемую.

Чтобы отправить данные из задачи, которую вы создали ранее, используйте это: async_to_sync(channel_layer.send)(channelName, {'type': 'sendData', 'text': jsonPayload}). Обратите внимание, как вы передаете имя канала, а также функцию sendData от своего потребителя.

Наконец, вот как будет выглядеть javascript на стороне клиента:

    let socket = new WebSocket("wss://javascript.info/article/websocket/demo/hello");
    
    socket.onopen = function(e) {
      alert("[open] Connection established");
      alert("Sending to server");
      socket.send("My name is John");
    };
    
    socket.onmessage = function(event) {
      alert(`[message] Data received from server: ${event.data}`);
    };
    
    socket.onclose = function(event) {
      if (event.wasClean) {
        alert(`[close] Connection closed cleanly, code=${event.code} reason=${event.reason}`);
      } else {
        // e.g. server process killed or network down
        // event.code is usually 1006 in this case
        alert('[close] Connection died');
      }
    };
    
    socket.onerror = function(error) {
      alert(`[error] ${error.message}`);
    };

Этот код взят непосредственно из этого JavaScript пошагового руководства по WebSocket.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...