Minua on aina häirinnyt Django-sovelluksissa yksi asia. Kun sovelluksen päivittää, sitä pyörittävä sovelluspalvelin (Gunicorn) täytyy käynnistää uudelleen. Tämä taas aiheuttaa pienen katkoksen palvelun toiminnassa. Jos joku sattuu juuri silloin lataamaan sivuston, hän saa 502 Bad Gateway -virheilmoituksen.

Lisää kiusaa aiheuttaa staattisten tiedostojen päivittäminen. Jos käytössä on esimerkiksi Django-mediagenerator, niin CSS/JS-tiedostot pitää generoida uudelleen muokkaamisen jälkeen. Tämä aiheuttaa pienen katkon niiden palvelemiseen.

Nyt päätin kokeilla, olisiko tämä kaikki helppo korjata jotenkin yksinkertaisesti, ja olihan se. Nginxissä on nimittäin optio, jolla voi määritellä backup-sovelluspalvelimen sen varalle, että oikea ei ole tavoitettavissa. Esimerkiksi näin:

upstream gunicorn_kfalcknet {
    server unix:/tmp/gunicorn-kfalcknet.sock fail_timeout=0;
    server unix:/tmp/gunicorn-fallback-kfalcknet.sock fail_timeout=0 backup;
}


Sovelluksen päivityksen hoitava skripti näyttää minun tapauksessani tältä:

#!/bin/sh

# Start fallback server and stop primary server
sudo /etc/init.d/gunicorn-fallback-kfalcknet start
sudo /etc/init.d/gunicorn-kfalcknet stop

# Update primary application
git pull
./manage.py generatemedia
./fixperms.sh

# Start primary server and stop fallback server
sudo /etc/init.d/gunicorn-kfalcknet start
sudo /etc/init.d/gunicorn-fallback-kfalcknet stop

# Update fallback application
cd ../fallback_kfalcknet
git pull
./manage.py generatemedia
./fixperms.sh
cd ../kfalcknet

Idea siis on, että Django-sovelluksen päivityksen ajaksi käynnistetään ennalta asennettu varapalvelin. Silloin pääpalvelin voidaan rauhassa sammuttaa ja päivittää. Pääpalvelimen käynnistyttyä varapalvelin voidaan jälleen sammuttaa ja ajaa samat päivitykset sinnekin.


Viimeinen tarvittava kohta on vielä Nginxin konfiguroiminen palvelemaan vanhoja staattisia tiedostoja päivityksen ajan. Sen olen tehnyt näin:

# mediagenerator file access
location /media {
    root /home/kennu/kfalcknet/_generated_media;
    rewrite ^/media(/.*) $1;
    index index.html;
    expires max;
    try_files $uri /fallback-media/$uri;
    break;
}

# fallback mediagenerator file access
location /fallback-media {
    root /home/kennu/fallback_kfalcknet/_generated_media;
    rewrite ^/fallback-media(/.*) $1;
    index index.html;
    expires max;
    break;
}

Toisin sanoen Nginx yrittää ensin palvella tiedostoja pääsovelluksen _generated_media-hakemistosta. Jos niitä ei löydy, niin sitten kokeillaan varapalvelimelta.


Disclaimaan tätä konfiguraatiota sen verran, että en ole oikeasti kokeillut sen vedenpitävyyttä millään testeillä. Django-mediageneratoriin liittyy myös se ongelma, että osa käyttäjistä voi vielä päivityksen jälkeen saada vanhoja CSS/JS-tiedostopolkuja jostakin välimuistista. Tuotantokäytössä olisi fiksumpaa, että myös vanhat versiot tiedostoista jäisivät varmuudeksi paikoilleen. Oletuksenahan mediagenerator poistaa kaiken vanhan _generated_media-hakemistosta.

Published 3.11.2012