Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit aeaf9d6
Showing
15 changed files
with
303 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
*.pyc | ||
*.sqlite3 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
Async Task Channels Demo | ||
======================== | ||
|
||
The demo goes with the talk [Async Tasks with Django | ||
Channels](http://albertoconnor.ca/pycon-canada-2016-talk.html) given | ||
at [PyCon Canada 2016](https://2016.pycon.ca/en/schedule/016-albert-oconnor/) | ||
|
||
It is split up into a few different step with tags so you can more | ||
easily see how it was built up. | ||
|
||
step1 | ||
----- | ||
|
||
git clone https://github.com/albertoconnor/asyncdemo.git | ||
cd asyncdemo | ||
git checkout step1 | ||
|
||
At this point, the code is for a basic Django 1.10 web app. Get into your | ||
favorite type of virtual env and then run the following. | ||
|
||
pip install -r requirements.text | ||
cd asyncdemo | ||
python manage.py migrate | ||
python manage.py runserver | ||
|
||
Now you should have the hello_view being served at | ||
http://127.0.0.1:8000/. You can append "?name=yourname" to change the | ||
name displayed. | ||
|
||
Meanwhile, there is a simulated slow network call which writes out the | ||
hello message to the console and takes between 5 and 30 seconds to | ||
do it. | ||
|
||
step2 | ||
----- | ||
|
||
git checkout step2 | ||
|
||
This has updated requirements.txt and settings.py and created a | ||
routes.py which is even to get Django to run with Channels. The view | ||
remains unchanged, so it will still be slow when you runserver. You can | ||
see though the output Django produces when you runserver has been | ||
changed. | ||
|
||
step 3 | ||
------ | ||
|
||
git checkout step3 | ||
|
||
A "notify" channel has been declared and the view now uses it. When you | ||
runserver the website is more responsive, but if you hammer it those | ||
slow 30 second simulated network calls will gum up the system. | ||
|
||
bonusround | ||
---------- | ||
|
||
git checkout bonusround | ||
|
||
This changes channels to use redis as the broker of messages. Even to | ||
runserver you will need to have redis running locally. | ||
|
||
When you do you will get the same behavior of step 3. To get around the | ||
slow down under load we will need to run everything in separate | ||
processes, in separate terminals. | ||
|
||
daphne asyncdemo.asgi:channel_layer --port 8000 | ||
|
||
This runs the interface server in it's own process. If you try to | ||
connect now it will time out because there are no workers running. | ||
|
||
You can run workers in as many separate terminals as you like: | ||
|
||
python manage.py runworker | ||
|
||
But the key to trying to maintain throughput is to run a worker which | ||
will never be tied up with a notification task: | ||
|
||
python manage.py runworker --exclude-channels=notify | ||
|
||
This worker will ensure that hello_view remains responsive. |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
""" | ||
Django settings for asyncdemo project. | ||
Generated by 'django-admin startproject' using Django 1.10.2. | ||
For more information on this file, see | ||
https://docs.djangoproject.com/en/1.10/topics/settings/ | ||
For the full list of settings and their values, see | ||
https://docs.djangoproject.com/en/1.10/ref/settings/ | ||
""" | ||
|
||
import os | ||
|
||
# Build paths inside the project like this: os.path.join(BASE_DIR, ...) | ||
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) | ||
|
||
|
||
# Quick-start development settings - unsuitable for production | ||
# See https://docs.djangoproject.com/en/1.10/howto/deployment/checklist/ | ||
|
||
# SECURITY WARNING: keep the secret key used in production secret! | ||
SECRET_KEY = 'ud9(^27w%&0j=1oe1kvp@i*1=y0#6#e!4dz^4sncz#pihs_%kt' | ||
|
||
# SECURITY WARNING: don't run with debug turned on in production! | ||
DEBUG = True | ||
|
||
ALLOWED_HOSTS = [] | ||
|
||
|
||
# Application definition | ||
|
||
INSTALLED_APPS = [ | ||
'django.contrib.admin', | ||
'django.contrib.auth', | ||
'django.contrib.contenttypes', | ||
'django.contrib.sessions', | ||
'django.contrib.messages', | ||
'django.contrib.staticfiles', | ||
'hello', | ||
] | ||
|
||
MIDDLEWARE = [ | ||
'django.middleware.security.SecurityMiddleware', | ||
'django.contrib.sessions.middleware.SessionMiddleware', | ||
'django.middleware.common.CommonMiddleware', | ||
'django.middleware.csrf.CsrfViewMiddleware', | ||
'django.contrib.auth.middleware.AuthenticationMiddleware', | ||
'django.contrib.messages.middleware.MessageMiddleware', | ||
'django.middleware.clickjacking.XFrameOptionsMiddleware', | ||
] | ||
|
||
ROOT_URLCONF = 'asyncdemo.urls' | ||
|
||
TEMPLATES = [ | ||
{ | ||
'BACKEND': 'django.template.backends.django.DjangoTemplates', | ||
'DIRS': [], | ||
'APP_DIRS': True, | ||
'OPTIONS': { | ||
'context_processors': [ | ||
'django.template.context_processors.debug', | ||
'django.template.context_processors.request', | ||
'django.contrib.auth.context_processors.auth', | ||
'django.contrib.messages.context_processors.messages', | ||
], | ||
}, | ||
}, | ||
] | ||
|
||
WSGI_APPLICATION = 'asyncdemo.wsgi.application' | ||
|
||
|
||
# Database | ||
# https://docs.djangoproject.com/en/1.10/ref/settings/#databases | ||
|
||
DATABASES = { | ||
'default': { | ||
'ENGINE': 'django.db.backends.sqlite3', | ||
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), | ||
} | ||
} | ||
|
||
|
||
# Password validation | ||
# https://docs.djangoproject.com/en/1.10/ref/settings/#auth-password-validators | ||
|
||
AUTH_PASSWORD_VALIDATORS = [ | ||
{ | ||
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', | ||
}, | ||
{ | ||
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', | ||
}, | ||
{ | ||
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', | ||
}, | ||
{ | ||
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', | ||
}, | ||
] | ||
|
||
|
||
# Internationalization | ||
# https://docs.djangoproject.com/en/1.10/topics/i18n/ | ||
|
||
LANGUAGE_CODE = 'en-us' | ||
|
||
TIME_ZONE = 'UTC' | ||
|
||
USE_I18N = True | ||
|
||
USE_L10N = True | ||
|
||
USE_TZ = True | ||
|
||
|
||
# Static files (CSS, JavaScript, Images) | ||
# https://docs.djangoproject.com/en/1.10/howto/static-files/ | ||
|
||
STATIC_URL = '/static/' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
from django.conf.urls import url | ||
|
||
from hello import views | ||
|
||
urlpatterns = [ | ||
url(r'^$', views.hello_view), | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
""" | ||
WSGI config for asyncdemo project. | ||
It exposes the WSGI callable as a module-level variable named ``application``. | ||
For more information on this file, see | ||
https://docs.djangoproject.com/en/1.10/howto/deployment/wsgi/ | ||
""" | ||
|
||
import os | ||
|
||
from django.core.wsgi import get_wsgi_application | ||
|
||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "asyncdemo.settings") | ||
|
||
application = get_wsgi_application() |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
from django.contrib import admin | ||
|
||
# Register your models here. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
from django.apps import AppConfig | ||
|
||
|
||
class HelloConfig(AppConfig): | ||
name = 'hello' |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
from django.db import models | ||
|
||
# Create your models here. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
<!doctype html> | ||
<html> | ||
<head> | ||
<meta charset="utf-8"/> | ||
<title>Asyc Demo</title> | ||
</head> | ||
|
||
<body> | ||
<h1>{{ message }}</h1> | ||
</body> | ||
|
||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
from django.test import TestCase | ||
|
||
# Create your tests here. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
import time | ||
from django.shortcuts import render | ||
|
||
|
||
def delay(): | ||
while True: | ||
for i in [5, 5, 5, 30]: # Simulate unreliability | ||
yield i | ||
|
||
|
||
delay_generator = delay() | ||
|
||
|
||
def send_notification(message): | ||
time.sleep(next(delay_generator)) | ||
print(message) # Simulate sending to slack etc. | ||
|
||
|
||
def hello_view(request, template="hello.html"): | ||
name = request.GET.get('name', 'World') | ||
message = 'Hello, {}!'.format(name) | ||
|
||
send_notification(message) | ||
|
||
return render( | ||
request, | ||
template, | ||
dict(message=message), | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
#!/usr/bin/env python | ||
import os | ||
import sys | ||
|
||
if __name__ == "__main__": | ||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "asyncdemo.settings") | ||
try: | ||
from django.core.management import execute_from_command_line | ||
except ImportError: | ||
# The above import may fail for some other reason. Ensure that the | ||
# issue is really that Django is missing to avoid masking other | ||
# exceptions on Python 2. | ||
try: | ||
import django | ||
except ImportError: | ||
raise ImportError( | ||
"Couldn't import Django. Are you sure it's installed and " | ||
"available on your PYTHONPATH environment variable? Did you " | ||
"forget to activate a virtual environment?" | ||
) | ||
raise | ||
execute_from_command_line(sys.argv) |