pyconmy 2016 django channels
TRANSCRIPT
![Page 2: PyConMY 2016 Django Channels](https://reader035.vdocument.in/reader035/viewer/2022062523/586e85821a28aba0038b63bf/html5/thumbnails/2.jpg)
About Me Also Director of Third Life Sdn. Bhd. – co-developer
of Mobile Marketing app for Businesses: channels.io
Web Applications - Django
Mobile Apps backend - Django
Point-of-Sales system (POS) - Django
POS Device Connectors - Tornado.
![Page 3: PyConMY 2016 Django Channels](https://reader035.vdocument.in/reader035/viewer/2022062523/586e85821a28aba0038b63bf/html5/thumbnails/3.jpg)
Objective
General overview of Channels
Simple Example
Scaling
![Page 4: PyConMY 2016 Django Channels](https://reader035.vdocument.in/reader035/viewer/2022062523/586e85821a28aba0038b63bf/html5/thumbnails/4.jpg)
What is Django Channels
“Channels is a project to make Django able to handle more than just plain HTTP requests, including WebSockets and HTTP2, as well as the ability to run code after a response has been sent for things like thumbnailing or background calculation.”- http://channels.readthedocs.io/
![Page 5: PyConMY 2016 Django Channels](https://reader035.vdocument.in/reader035/viewer/2022062523/586e85821a28aba0038b63bf/html5/thumbnails/5.jpg)
Web Applications Activities / Tasks
Respond to request (GET, POST, …)
Batch activities – slower tasks such as sending email etc.
Web Sockets
![Page 6: PyConMY 2016 Django Channels](https://reader035.vdocument.in/reader035/viewer/2022062523/586e85821a28aba0038b63bf/html5/thumbnails/6.jpg)
Python Frameworks / Libraries
Respond to request (GET, POST, …) DJANGO
Batch processing Celery, RQ, Gearman
Web Sockets Flask, Tornado, Twisted
![Page 7: PyConMY 2016 Django Channels](https://reader035.vdocument.in/reader035/viewer/2022062523/586e85821a28aba0038b63bf/html5/thumbnails/7.jpg)
Vanilla Django Built around
Requests and Responses
Incompatible with WebSockets.
Source: https://blog.heroku.com/in_deep_with_django_channels_the_future_of_real_time_apps_in_django
![Page 8: PyConMY 2016 Django Channels](https://reader035.vdocument.in/reader035/viewer/2022062523/586e85821a28aba0038b63bf/html5/thumbnails/8.jpg)
Django Channels Addition of Async Interface
Server and Channels Layer (Asynchronous Server Gateway Interface)
Worker Processes able to handle Request / Response, WebSocket and Background Processes
Existing concepts of views still applies to Request & Response
Source: https://blog.heroku.com/in_deep_with_django_channels_the_future_of_real_time_apps_in_django
![Page 9: PyConMY 2016 Django Channels](https://reader035.vdocument.in/reader035/viewer/2022062523/586e85821a28aba0038b63bf/html5/thumbnails/9.jpg)
Side-by-Side
Vanilla Django Django Channels
Daphne
In-Memory / IPC / Redis
![Page 10: PyConMY 2016 Django Channels](https://reader035.vdocument.in/reader035/viewer/2022062523/586e85821a28aba0038b63bf/html5/thumbnails/10.jpg)
Why Django Channels? Pros
Consolidate and centralize configuration and program code Easier re-use Asynchronous in nature but you still write synchronous
code – no yields, monkey-patching etc. In one big package, so improvements and directions can
be aligned.
Cons Celery more complete compared to what Channels has to
offer Channels Layer choices still limited (IPC, Redis) Stuck in an Opinionated Framework
![Page 11: PyConMY 2016 Django Channels](https://reader035.vdocument.in/reader035/viewer/2022062523/586e85821a28aba0038b63bf/html5/thumbnails/11.jpg)
Example app for Django Channels Borrowed code from
https://github.com/jacobian/channels-example/
Covers: Traditional Request Response
(TemplateViews) Batch (fake email sending) WebSockets
![Page 12: PyConMY 2016 Django Channels](https://reader035.vdocument.in/reader035/viewer/2022062523/586e85821a28aba0038b63bf/html5/thumbnails/12.jpg)
Getting Started
pip install channels pip install asgi_redis
settings.py
CHANNEL_LAYERS = { "default": { "BACKEND": "asgi_redis.RedisChannelLayer", "CONFIG": { "hosts": [‘redis://localhost:6379’], }, "ROUTING": "main.routing.default_routing", }}
![Page 13: PyConMY 2016 Django Channels](https://reader035.vdocument.in/reader035/viewer/2022062523/586e85821a28aba0038b63bf/html5/thumbnails/13.jpg)
Routingrouting.py
from channels.routing import routefrom . import consumersfrom . import batch
channel_routing = [ route('send-invite', batch.send_invite),]
chat_routing = [ route('websocket.connect', consumers.ws_connect), route('websocket.receive', consumers.ws_receive), route('websocket.disconnect', consumers.ws_disconnect),]
default_routing = channel_routing + chat_routing
![Page 14: PyConMY 2016 Django Channels](https://reader035.vdocument.in/reader035/viewer/2022062523/586e85821a28aba0038b63bf/html5/thumbnails/14.jpg)
asgi.pyimport osimport channels.asgi
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "channels_test.settings")
channel_layer = channels.asgi.get_channel_layer()
![Page 15: PyConMY 2016 Django Channels](https://reader035.vdocument.in/reader035/viewer/2022062523/586e85821a28aba0038b63bf/html5/thumbnails/15.jpg)
Excerpt of views.py class InviteView(TemplateView): template_name = "invite.html"
def post(self, request, *args, **kwargs): context = self.get_context_data() REQUEST_DATA = request.POST email = REQUEST_DATA.get('email') if not email: context['error'] = "Email field not provided" return super(TemplateView, self).render_to_response(context)
data = { 'email': email, 'message': u"Hi, %s, you're invited!! Check us out at http://www.solutionx.com.my for more info!" % email } Channel('send-invite', alias=settings.BATCH_CHANNEL_LAYER).send(data) context['message'] = "We're sending the invite for you!" return super(TemplateView, self).render_to_response(context)
![Page 16: PyConMY 2016 Django Channels](https://reader035.vdocument.in/reader035/viewer/2022062523/586e85821a28aba0038b63bf/html5/thumbnails/16.jpg)
batch.py
import loggingimport time
logger = logging.getLogger('email')
def send_invite(message): logger.info("We receive a request to send email to: " + message.get('email')) logger.info("Message: " + message.get('message')) time.sleep(10) logger.info("Email sent successfully!")
![Page 17: PyConMY 2016 Django Channels](https://reader035.vdocument.in/reader035/viewer/2022062523/586e85821a28aba0038b63bf/html5/thumbnails/17.jpg)
Running the processes1. redis-server
2. daphne main.asgi:channel_layer
3. python manage.py runworker
![Page 18: PyConMY 2016 Django Channels](https://reader035.vdocument.in/reader035/viewer/2022062523/586e85821a28aba0038b63bf/html5/thumbnails/18.jpg)
Scaling
1. Add more workers
2. Redis sharding (seems to still require further testing)
3. Multiple Channel Layers
![Page 19: PyConMY 2016 Django Channels](https://reader035.vdocument.in/reader035/viewer/2022062523/586e85821a28aba0038b63bf/html5/thumbnails/19.jpg)
Scaling1. Add more workers
- python manage.py runworker
![Page 20: PyConMY 2016 Django Channels](https://reader035.vdocument.in/reader035/viewer/2022062523/586e85821a28aba0038b63bf/html5/thumbnails/20.jpg)
Scaling (2)1. Redis sharding (still requires further
testing)
![Page 21: PyConMY 2016 Django Channels](https://reader035.vdocument.in/reader035/viewer/2022062523/586e85821a28aba0038b63bf/html5/thumbnails/21.jpg)
Redis Sharding
CHANNEL_LAYERS = { "default": { "BACKEND": "asgi_redis.RedisChannelLayer", "CONFIG": { "hosts": ['redis://localhost:6379', 'redis://localhost:7777'], }, "ROUTING": "main.routing.default_routing", }}
![Page 22: PyConMY 2016 Django Channels](https://reader035.vdocument.in/reader035/viewer/2022062523/586e85821a28aba0038b63bf/html5/thumbnails/22.jpg)
Running the processes (Sharding)
1. redis-server2. redis-server --port 7777
3. daphne main.asgi_sharding:channel_layer
4. python manage.py runworker --settings channels_test.settings_sharding
5. python manage.py runworker --settings channels_test.settings_sharding
![Page 23: PyConMY 2016 Django Channels](https://reader035.vdocument.in/reader035/viewer/2022062523/586e85821a28aba0038b63bf/html5/thumbnails/23.jpg)
Scaling (3)1. Multiple Channel Layers
![Page 24: PyConMY 2016 Django Channels](https://reader035.vdocument.in/reader035/viewer/2022062523/586e85821a28aba0038b63bf/html5/thumbnails/24.jpg)
Multiple Channel LayersCHANNEL_LAYERS = { "test": { "BACKEND": "asgi_redis.RedisChannelLayer", "CONFIG": { "hosts": [‘redis://localhost:6379’], }, "ROUTING": "main.routing.channel_routing", }, "chat": { "BACKEND": "asgi_redis.RedisChannelLayer", "CONFIG": { "hosts": [`redis://localhost:7777’], }, "ROUTING": "main.routing.chat_routing", },}
![Page 25: PyConMY 2016 Django Channels](https://reader035.vdocument.in/reader035/viewer/2022062523/586e85821a28aba0038b63bf/html5/thumbnails/25.jpg)
Running the processes (Multiple Channel Layers)1. redis-server2. redis-server --port 7777
3. daphne -b 0.0.0.0 -p 8000 main.asgi_test:channel_layer4. python manage.py runworker --settings
channels_test.settings_prod --layer test --only-channels http.request
5. python manage.py runworker --settings channels_test.settings_prod --layer test --only-channels send-invite
6. daphne -b 0.0.0.0 -p 8080 main.asgi_chat:channel_layer7. python manage.py runworker --settings
channels_test.settings_prod --layer chat
![Page 26: PyConMY 2016 Django Channels](https://reader035.vdocument.in/reader035/viewer/2022062523/586e85821a28aba0038b63bf/html5/thumbnails/26.jpg)
Wrapping Up New but promising Hopefully makes writing complex web apps
easier
References: https://blog.heroku.com/
in_deep_with_django_channels_the_future_of_real_time_apps_in_django
http://www.machinalis.com/blog/introduction-to-django-channels/
http://channels.readthedocs.io/en/latest/ https://github.com/andrewgodwin/channels
![Page 27: PyConMY 2016 Django Channels](https://reader035.vdocument.in/reader035/viewer/2022062523/586e85821a28aba0038b63bf/html5/thumbnails/27.jpg)
Q&A
Chew Kok HoorDirector
channels.io App (not related to Django Channels, name similarity purely co-incidental)
http://channels.io
Android