Cook django with aiohttp workers
There is some standart stack to run django in production. For python 2, it is nginx + gunicorn or uwsgi + monkey patching libs, such as gevent or eventlet. Generally, I prefer gunicorn + eventlet, but when you switch (or start) django project on latest python 3.5, eventlet can do some bad magic. And you can switch to a new built-in mechanism, called aiohttp. Based on gunicorn docs, you need simply switch worker to gaiohttp and that’s all.
Then, something bad happens.
Answer is very simple: you write some memoryleaking code gaiohttp ignores max_requests option.
In other words, workers won’t be killed after max_requests count. After some search on internet, there is an article from asyncio contributor about copy-n-pasting worker from aiohttp repo to gunicorn.
Aiohttp docs says that you should use aiohttp.worker.GunicornWebWorker
, but when you switch setting there will be error.
[5898] [ERROR] Exception in worker process
Traceback (most recent call last):
File "./gunicorn/arbiter.py", line 557, in spawn_worker
worker.init_process()
File "./aiohttp/worker.py", line 37, in init_process
super().init_process()
File "./gunicorn/workers/base.py", line 132, in init_process
self.run()
File "./aiohttp/worker.py", line 40, in run
self.loop.run_until_complete(self.wsgi.startup())
AttributeError:
'WSGIHandler' object has no attribute 'startup'
So aiohttp.worker.GunicornWebWorker differs from standart wsgi app for django. Luckily, python community has two packages to overcome these difficulties: aiohttp-wsgi and aiodjango, add them to your requirements.txt. After this modify your wsgi.py according to docs:
import os
from django.core.wsgi import get_wsgi_application
from aiodjango import get_aio_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'settings')
# Build WSGI application
# Any WSGI middleware would be added here
application = get_wsgi_application()
# Build aiohttp application
app = get_aio_application(application)
That’s all folks.