Перевод: Introduction to Django channels

Django является блестящим веб-фреймворк. На самом деле это мой самый любимый по разным причинам. Полтора года назад, я переключился на Python и Django для всех моих веб-разработок. Я большой поклонник его эко системы и того что в эту эко систему входит большое количество пакетов сторонних производителей. В частности, я использую Django REST Framework всякий раз, когда мне нужно создать API. Раньше можно было бы сказать, что Django было более чем достаточно для создания и обслуживание основных HTTP запросов . Но веб изменился. Теперь у нас есть HTTP / 2 и веб-сокеты. Django не может поддержать их. Для веб-сокетов, я обычно использовал Торнадо или NodeJS (с отличной библиотекой Socket.io). Это хорошие технологии, но большинство моих веб-приложений, созданы на Django, и я хотел что-то, что может работать с Django. И затем появились Channels. Проект призван позволить Django поддерживать HTTP / 2, WebSockets или другие протоколы.

Концепция

Основная концепция очень проста — есть каналы и есть сообщения, есть производители и есть потребители — вся система основана на передаче сообщений по каналам а потребители реагируют на эти сообщения.

Давайте посмотрим на основные компоненты Django Channels:

  • канал (channel) — Канал как структуры данных представляет собой очередь FIFO. У нас может быть много каналов в зависимости от наших потребности.
  • сообщение (message) — Сообщение содержат значимые данные для потребителей. Сообщения передаются по каналам.
  • потребитель (consumer) — Потребитель, как правило, это функция, которая потребляет сообщение и реагируют на них.
  • сервер интерфейса (interface server) — Сервер интерфейса знает, как обращаться с различными протоколами. Он работает в качестве переводчика или моста между Django и внешним миром.

Как это работает?

Запрос HTTP сначала приходит на сервер интерфейса, который знает, что делать с запросами определенных типом . Например, Daphne популярный сервер интерфейса для WebSockets и HTTP. Когда новый HTTP / WebSocket запрос приходит на сервер интерфейса (Daphne в нашем случае), он принимает запрос и преобразует его в сообщение. Затем он передает сообщение в соответствующий канал. Есть предустановленные каналы для определенных типов. Например, все запросы HTTP передаются на канал http.request. Для входящих сообщений WebSocket, есть websocket.receive.

Теперь, после того как на каналы поступят сообщениями, нам нужен способ обработать эти сообщения, не так ли? Для этого мы создаем какие нибудь функции потребителей и регистрируем их на каналы. Теперь когда сообщения приходят на эти каналы, они передаются потребителям.

Мы рассмотрели обработку входящего запроса. Но как и все веб-приложения, мы должны что то возвращать. Сервер интерфейса в то время как он преобразует входящий запрос в сообщение, он так создает ответный канал для этого конкретного запроса и регистрирует себя в этом канале. Затем он передает канал ответа вместе с сообщением. Когда наш потребитель читает входящее сообщение, он может передать ответ через канал ответа который прилагается с сообщением. Сервер интерфейса слушает этот канал ответа. Так что, когда ответ отправляется обратно на канал ответа, сервер интерфейса захватывает сообщение, преобразует его в ответ HTTP и отправляет обратно клиенту. Просто, не так ли?

Создание Websocket Echo Server

Достаточно теории, давайте создадим простой echo server. Его концепция будет достаточно простой. Сервер принимает websocket конекты, клиент посылает что то на сервер а сервер будет возвращает это же обратно.

Инсталяция Django и Channels

Это команда установит Django и Channels. Channels имеют в зависимостях Django поэтому при инсталяции channels, так же поставиться и Django.

Создание приложения

Далее создадим новый django проект и наше приложение

Конфигурирование INSTALLED_APPS

Нам нужно добавить каналы и django приложение (realtime) в INSTALLED_APPS в файле настроек settings.py:

Создание нашего потребителя

После этого, нам нужно написать функцию потребителя которая будет обрабатывать входящие websocket сообщения и отсылать обратно ответ:

Код достаточно простой. Мы получаем сообщение, берем из него текстовый контент (в этом примере мы ожидаем что через websocket будут приходить только текстовые данные) и затем отправляем их обратно через reply_channel.

Маршруты каналов

Сейчас нам нужно сказать Django как отправлять сообщения нашему потребителю. Так же как и URL маршрутизация, нам нужно определить маршрутизацию для каналов.

У нас есть список маршрутов. Здесь мы выбираем имя канала (websocket.receive => для получения websocket сообщений), указываем функцию потребителя и затем указывать путь. Если мы не укажим путь, потребитель будет получать все сообщения канала websocket.receive через любой URL. Если кто то создаст websocket с путем / или /private или /user/1234 — наш потребитель так же получать все эти сообщения. Обратите внимание что путь начинается с  /, в отличие url маршрутизации, в каналах, мы должны использовать слеш.

Конфигурирование Channel Layers

Мы определили потребителя и добавили его в таблицу роутинга. У нас почти все готово. Остался последний штрих. Нам нужно сказать каналам две вещи — какой сервер интерфейса мы будем использовать и где находится роутинг.

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

И пропишем его в настройках settings.py:

Запуск серверов

Убедитесь что Redis запущен (для запуска обычно используется команда redis-server ). И потом запустите django приложение:

Попробуем как это работает!

После того как сервер запуститься, откроете наше веб приложение. Если вы не добавляли ни одной django вьюхи, вы должны увидеть welcome страницу с текстом “It Worked!”. Теперь нам нужно протестировать websocket мы можем это сделать с консоли. Откройте Chrome Devtools (или Firefox | Safari ) и перейдите к JS консоли. Вставте следующий JS код:

Если все работает как должно, вы должны получить alert с тем же сообщением что вы послали. Так как мы определили путь, то websocket работает только с /chat/. Попытайтесь изменить JS код и отправить сообщение на другой url и это не должно сработать.

Наши собственные каналы

Мы видели, что некоторые протоколы имеют заранее определенные каналы для различных целей. Но мы не ограничены ими. Мы можем создать наши собственные каналы. Нам не нужно делать что-либо особенное, чтобы инициализировать новый канал. Нам просто нужно упомянуть его имя и отправить некоторые сообщения к нему. Django создаст канал для нас.

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

Расширение масштабов системы

Запуск Workers отдельно

В производственной среде, нам нужно, запустить workers отдельно (так как мы не будем запускать runserver). Для фонового запуска workers, мы должны выполнить эту команду:

ASGI и Daphne

В нашей локальной среде, команда runserver позаботится о запуске сервера интерфейса и фоновый workers. Но теперь мы нужно самим запускать сервер интерфейса. Мы уже упоминали Daphne. Он работает со стандартом ASGI (который обычно используется для HTTP / 2 и WebSockets). Так же, как wsgi.py, теперь нам нужно создать модуль asgi.py и настроить его.

Сейчас мы можем запустить сервер:

ASGI или WSGI

ASGI все еще является достаточно новым подходом. Вы можете продолжать использовать WSGI для HTTP и ASGI там где вам нужны каналы.

Популярная рекомендация состоит в том, что вы должны использовать Nginx или любые другие обратные прокси-сервера на фронтенде и маршрутизацию к ASGI url или uwsgi в зависимости от URL или заголовок Upgrade: WebSocket.

Повторы и Celery

Система каналов не гарантируем доставку. Если есть задачи, которые нуждается в гарантиях доставки, настоятельно рекомендуется использовать Celery для этого. Или вы можете использовать ваши собственные проверки доставки и логику повторений запросов.

It's only fair to share...Share on FacebookShare on Google+Tweet about this on TwitterShare on LinkedInShare on VK