uWSGI is a fast (pure C code) and self-healing solution for python apps, but it's not easy to use.
How does it work?
uWSGI operates on a client-server model. Your Web server (e.g., Nginx, Apache) communicates with a django-uwsgi “worker” process to serve dynamic content. In the configuration of uWSGI, you can decide how many workers (processes, threads) you want for your app. Try to follow all the configs that I share because default values are all wrong (you should check this europython talk to know more about it).
How can I run it?
uWSGI supports multiple ways to configure the process.
uwsgi --chdir=/path/to/your/project \ --module=mysite.wsgi:application \ --env DJANGO_SETTINGS_MODULE=mysite.settings \ --master --pidfile=/tmp/project-master.pid \ --socket=127.0.0.1:49152 \ # can also be a file --processes=5 \ # number of worker processes --uid=1000 --gid=2000 \ # if root, uwsgi can drop privileges --harakiri=20 \ # respawn processes taking more than 20 seconds --max-requests=5000 \ # respawn processes after serving 5000 requests --vacuum \ # clear environment on exit --home=/path/to/virtual/env \ # optional path to a virtualenv --daemonize=/var/log/uwsgi/yourproject.log # background the process
Or you can run your application with a config file (.ini) like this:
uwsgi --ini uwsgi.ini
[uwsgi] # If you want to use it with nginx-proxy (jwilder) and VIRTUAL_PROTO # for running inside of docker socket = 0.0.0.0:8000 #http-socket = 0.0.0.0:8000 # if you dont want to run it with sudo uid=uwsgi gid=uwsgi # for naming auto-procname=true procname-prefix=eduzen- # clear environment on exit vacuum = true # check sintax error on this file strict=true # master uWSGI’s built-in prefork+threading multi-worker management mode master = true # allows threading module on python (not only for our code also for third-parties) enable-threads=true # accpets kill signal SIGTERM die-on-term=true # checks if the app is up need-app=true # there are reports on some C extensions that do not cooperate well with multiple interpreters single-interpreter=true # logss are super noisy disable-logging=true log-4xx=true log-5xx=true logformat="%(method) %(uri) %(proto) %(status)" %(user) %(addr) %(uagent) from %(referer) # Workers (these can be processes and threads but because of GIL is better to go for processes) # How many? cpu cores * 2 (but it needs to be checked by running uwsgitop /tmp/uwsgi-stats.socket) processes = 2 # restart workers after this many requests max-requests=5000 # restart worker after this many seconds max-worker-lifetime=3600 # restart worker after this much of resident memory reload-on-rss=2048 # How many minutes uwgsi needs to wait before forcefully killing workers worker-reload-mercy=10 # forcefully kill workers after 20 seconds. SIGKILL if the worker doesnt respond harakiri=20 post-buffering=true # allow the workers to recieve signals such as signal.alarmm from the OS (not working for alpine) # py-call-osafterfork=true wsgi-disable-file-wrapper=false # Django-related settings # the base directory (full path) chdir=/code/website # Django's wsgi file module=website.wsgi # the virtualenv (full path) # home=/usr/local/bin/ # Track statistics for easier peformance tuning #stats = /tmp/uwsgi-stats.socket #touch-reload = /tmp/reload-uwsgi
Gunicorn is easy for starting a project. But if you have more time and you want to have the possibility of better setups go for uwsgi. Try to read carefully the docs!
How to debug it?
There is a great tool for debugging uWsgi: uwsgitop is a top-like command that uses the stats server. It is available on PyPI, so use
pip to install it. You can check the code: https://github.com/xrmx/uwsgitop
#To use uWSGI Stat Server simply use the stats option followed by a valid socket address, # for example: uwsgi --module myapp --socket :3030 --stats /tmp/stats.socket # To start monitoring your application with uwsgitop call it with the socket address like so: uwsgitop /tmp/stats.socket # If you want the stats served over HTTP you will need to add the stats-http option in uWSGI: uwsgi --module myapp --http :3030 --stats :3031 --stats-http # You'll now need to call uwsgitop as: uwsgitop http://127.0.0.1:3031