Sanic builtin server deployment best practice. Ubuntu

Hi everyone.
I need help deploying Sanic application to Ubuntu server.
This is not exactly Sanic specific question, but this information could be useful for all Sanic users.

I successfully packed and published my application to PyPi repository.
Pip installation on Ubuntu server went smoothly and my application works.
I specifically want to use the builtin Sanic server.

Currently i run application like so -

sudo python3 main.py --host=10.128.0.34 --port=8080

Now I need to make sure, that Sanic server runs always -

  1. If VM is restarted - the Sanic must start aswell
  2. If Sanic crushes - it must be restarted
  3. If Sanic hangs - it must be restarted

Unfortunately, I little experience with Linux systems and definitely could use some help.

How should I configure Ubuntu server in production to guaranty that my Sanic application always running?

Have you read the deploying guide at https://sanic.readthedocs.io/en/latest/sanic/deploying.html ?

Personally, I use a systemd config that auto restart and have it run gunicorn that bind it to my desired port, and use nginx as a reverse proxy.

I don’t know if that’s considered “Best Practice,” so I am curious to hear what other people do also.

Currently, I ended up with using monit.
(https://github.com/arnaudsj/monit)

I created bash script - ax.sh

#!/bin/bash

process=$1
PID_FILE="/home/wineuser/.local/lib/python3.6/site-packages/ax/ax.pid"
case $process in
    start)
        echo "STARTING Ax server - port 8080"
        python3 /home/wineuser/.local/lib/python3.6/site-packages/ax/main.py --host=10.128.0.34 --port=8080 &
        echo $! > $PID_FILE
        ;;
    stop)
        kill -9 $(cat $PID_FILE)
        rm $PID_FILE
        ;;
    *)
        echo "INVALID OPTION"
        ;;
esac

Then I modified monit configuration file at /etc/monit/monitrc and added -

  check host ax with address 84.201.174.246
    start program = "/home/wineuser/.local/lib/python3.6/site-packages/ax/ax.sh start"
    stop program = "/home/wineuser/.local/lib/python3.6/site-packages/ax/ax.sh stop"
    if failed port 8080 protocol http
       and request /deck
    then restart

Now, every 2 minutes monit checks if my application is available by HTTP. If it is not - is starts the application.

I am not sure this is a good solution. I would really like to hear what are other options out there.

I use Nginx as a reverse proxy and supervisor to manage python processes(the python server which holds the sanic app) in production.All we need is some configurations.

Nginx’s duty is to pass the request to the guy who can actually hadle the request as a reverse proxy. Nginx also need to handle the access log cause it also play a role as a gateway.

  • Nginx config

    # you shoud create you own .conf file in /etc/nginx/conf.d/
    
    # load balancing.Won't use
    upstream sanic {
        server 127.0.0.1:5000;
        server 127.0.0.1:5001;
        }
    
    # Only listen to 4000 cause I use sanic to write some restful APIs
    server {
        listen 4000;
        location / {
                proxy_pass http://sanic;  # pass to sanic i.e. 127.0.0.1: 5000/5001
                proxy_set_header Host $host;
                proxy_set_header X-Real-IP $remote_addr;
        }
        add_header 'Access-Control-Allow-Headers' '*';
        add_header 'Access-Control-Allow-Origin' '*';
    }
    

Gunicorn is the guy who actually handle the request since it’s hold the sanic app. (sanic server and uvicorn is the same)

  • gunicorn config

    import multiprocessing
    import os
    
    bind = '127.0.0.1:5000'
    
    debug = False
    
    # number of worker
    workers = multiprocessing.cpu_count() * 2 + 1
    worker_class = 'sanic.worker.GunicornWorker'
    
    x_forwarded_for_header = 'X-FORWARDED-FOR'
    
    # timeout
    timeout = 30
    
  • the sanic app should be run like

    gunicorn yourPythonFile:youAppObject -c gunicorn.py
    

Supervisord is a general process management tool, we can use it to manage the gunicorn process easily.

  • the supervisord config

    ; add some configurations after /etc/supervisord.conf
    [program:gunicorn]
    ; numprocs=1
    ; process_name=%(program_name)s_%(process_num)02d;
    directory=/youProjectPath
    command=gunicorn yourPythonFile:youAppObject -c gunicorn.py
    user=ubuntu
    startsecs=0
    stopwaitsecs=0
    ; start the process once the supervisord is started
    autostart=true
    ; restart the process once the process is killed or exited
    autorestart=true
    
  • start the supervisord

    sudo supervisord -c /etc/supervisord.conf
    
  • manage the processes by supervisorctl

    sudo supervisorctl
    

once you enter the supervisorctl console, you should be able to use some commands.

  • status/start/restart/reload/…

the gunicorn shoule be started by start gunicorn command

PS:

  1. the supervisord only care the master process, it dones’t konw the status of the workers, so it only restart the process when the master process is shutdown.
  • the gunicorn worker will be restart by it’s own master when the woker is dead or reach the max request time meanwhile the sanic server master won’t restart the worker, the sanic master will exit when all the worker is shutdown(then the supervisord should restart the sanic server).

  • I didn’t find anyway to make the sanic master to restart the worker

  1. I wonder that will gunicorn slow performance of sanic? I want to use uvicorn the deploy sanic asgi app but I found some compatibility issues.

  2. the deployment above is exactly the deployment I use in reallife production(but we deploy odoo application instead of sanic).

2 Likes