Pour mon déploiement actuel de flacon, j'ai dû configurer un serveur uwsgi. Voici comment j'ai créé le démon uwsgi:
Sudo vim /etc/init/uwsgi.conf
# file: /etc/init/uwsgi.conf
description "uWSGI server"
start on runlevel [2345]
stop on runlevel [!2345]
respawn
exec /myproject/myproject-env/bin/uwsgi --uid www-data --gid www-data --home /myproject/myproject-env/site/F11/Engineering/ --socket /tmp/uwsgi.sock --chmod-socket --module F11 --callable app --pythonpath /myproject/myproject-env/site/F11/Engineering/ -H /myproject/myproject-env
Cependant, après avoir exécuté ceci avec succès: Sudo start uwsgi
uwsgi start/running, process 1286
Et en essayant d'accéder à l'application via un navigateur:
Je reçois un 502 Bad Gateway
et une entrée d'erreur dans nginx error.log:
2013/06/13 23:47:28 [erreur] 743 # 0: * 296 en amont de la connexion prématurément fermée Lors de la lecture de l'en-tête de la réponse en amont, client: Xx.161.xx.228, serveur: myproject.com, requête: "GET/show_records/2013/6 HTTP/1.1", en amont: "uwsgi: // unix: ///tmp/uwsgi.sock:", hôte: "myproject .com "
Mais le fichier chaussette a la permission nécessaire:
srw-rw-rw- 1 www-data www-data 0 Jun 13 23:46 /tmp/uwsgi.sock
Si je lance la commande exec
depuis le haut dans la ligne de commande en tant que processus, cela fonctionne parfaitement. Pourquoi le démon ne fonctionne pas correctement s'il vous plaît?
btw Nginx est en cours d'exécution en tant que vim /etc/nginx/nginx.conf
user www-data;
et vim /etc/nginx/sites-available/default
location / {
uwsgi_pass unix:///tmp/uwsgi.sock;
include uwsgi_params;
}
et il est lancé comme Sudo service nginx start
J'exécute ceci sur Ubuntu 12.04 LTS
.
J'espère avoir fourni toutes les données nécessaires, j'espère que quelqu'un pourra me guider dans la bonne direction. Merci.
Enfin, j'ai résolu ce problème après avoir travaillé près de 2 jours dessus. J'espère que cette solution aidera d'autres utilisateurs de flask/uwsgi qui rencontrent un problème similaire.
J'ai eu deux problèmes majeurs qui ont causé cela.
1) La meilleure façon de trouver les problèmes avec un démon est évidemment un fichier journal et une structure plus propre.
Sudo vim /etc/init/uwsgi.conf
Modifiez le script démon comme suit:
# file: /etc/init/uwsgi.conf
description "uWSGI server"
start on runlevel [2345]
stop on runlevel [!2345]
respawn
exec /home/ubuntu/uwsgi-1.9.12/uwsgi -c /myproject/uwsgi.ini
vim /myproject/uwsgi.ini
[uwsgi]
socket = /tmp/uwsgi.sock
master = true
enable-threads = true
processes = 5
chdir= /myproject/F11/Engineering
module=F11:app
virtualenv = /myproject/myproject-env/
uid = www-data
gid = www-data
logto = /myproject/error.log
C'est une manière beaucoup plus propre de configurer le démon. Notez également la dernière ligne pour savoir comment configurer le fichier journal. Initialement, j'avais défini le fichier journal sur /var/log/uwsgi/error.log
. Après beaucoup de sueur et de larmes, j'ai réalisé que le démon fonctionnait sous le nom www-data
et ne pouvait donc pas accéder au /var/log/uwsgi/error.log
puisque le fichier error.log appartenait à root:root
. Cela a fait échouer les uwsgi en silence.
J'ai trouvé beaucoup plus efficace de simplement pointer le fichier journal sur mon propre /myproject
, où le démon a l'accès garanti en tant que www-data
. Et n'oubliez pas de rendre le projet entier accessible à www-data
sinon le démon échouera avec un Internal Server error message
. ->
Sudo chown www-data:www-data -R /myproject/
Redémarrez le démon uwsgi:
Sudo service uwsgi restart
2) Vous avez maintenant trois fichiers journaux à surveiller:
tail -f /var/log/upstart/uwsgi.log
-> Affiche les problèmes avec votre démon au démarrage
tail -f /var/log/nginx/error.log
-> Affiche les problèmes de permission lorsque l'accès à wsgi est refusé, souvent parce que le fichier /tmp/uwsgi.sock
appartient à root
au lieu de www-data
. Dans ce cas, supprimez simplement le fichier chaussette Sudo rm /tmp/uwsgi.sock
tail -f /myproject/error.log
-> Affiche les erreurs générées par uwsgi dans votre application
Cette combinaison de fichiers journaux m'a aidée à comprendre que j'avais également une mauvaise importation avec Flask-Babel dans mon application Flask. Mauvais dans ce sens, que la façon dont j'ai utilisé la bibliothèque était de retour aux paramètres régionaux du système pour déterminer le format de date/heure.
File "/myproject/F11/Engineering/f11_app/templates/show_records.html", line 25, in block "body"
<td>{{ record.record_date|format_date }}</td>
File "./f11_app/filters.py", line 7, in format_date
day = babel_dates.format_date(value, "EE")
File "/myproject/myproject-env/local/lib/python2.7/site-packages/babel/dates.py", line 459, in format_date
return pattern.apply(date, locale)
File "/myproject/myproject-env/local/lib/python2.7/site-packages/babel/dates.py", line 702, in apply
return self % DateTimeFormat(datetime, locale)
File "/myproject/myproject-env/local/lib/python2.7/site-packages/babel/dates.py", line 699, in __mod__
return self.format % other
File "/myproject/myproject-env/local/lib/python2.7/site-packages/babel/dates.py", line 734, in __getitem__
return self.format_weekday(char, num)
File "/myproject/myproject-env/local/lib/python2.7/site-packages/babel/dates.py", line 821, in format_weekday
return get_day_names(width, context, self.locale)[weekday]
File "/myproject/myproject-env/local/lib/python2.7/site-packages/babel/dates.py", line 69, in get_day_names
return Locale.parse(locale).days[context][width]
AttributeError: 'NoneType' object has no attribute 'days'
Voici comment j’utilisais le filtre Flask:
import babel.dates as babel_dates
@app.template_filter('format_date')
def format_date(value):
day = babel_dates.format_date(value, "EE")
return '{0} {1}'.format(day.upper(), affix(value.day))
Le plus étrange est que ce code fonctionne parfaitement dans l'environnement de développement (!). Cela fonctionne même très bien lorsque vous exécutez uwsgi en tant que processus racine à partir de la ligne de commande. Mais il échoue lorsqu'il est exécuté par le démon www-data. Cela doit avoir quelque chose à voir avec la configuration des paramètres régionaux, ce à quoi Flask-Babel tente de se replier.
Lorsque j'ai modifié l'importation de cette façon, tout a finalement fonctionné avec le démon:
from flask.ext.babel import format_date
@app.template_filter('format_date1')
def format_date1(value):
day = format_date(value, "EE")
return '{0} {1}'.format(day.upper(), affix(value.day))
Par conséquent, soyez prudent lorsque vous utilisez Eclipse/Aptana Studio qui tente de choisir le bon espace de noms pour vos classes dans le code. Ça peut vraiment devenir moche.
Il fonctionne maintenant parfaitement comme un démon uwsgi sur un Amazon Ec2 (Ubuntu 12.04) depuis 2 jours. J'espère que cette expérience aidera les autres développeurs Python.
J'ai abandonné, aucun fichier uwsgi.log n'a été généré et nginx a continué à se plaindre à propos de:
2014/03/06 01:06:28 [error] 23175#0: *22 upstream prematurely closed connection while reading response header from upstream, client: client.IP, server: my.server.IP, request: "GET / HTTP/1.1", upstream: "uwsgi://unix:/var/web/the_gelatospot/uwsgi.sock:", Host: "Host.ip"
pour chaque demande. Cela ne s'est produit que si uwsgi était exécuté en tant que service. En tant que processus, il a bien démarré sous n'importe quel utilisateur. Donc, cela fonctionnerait en ligne de commande (la page répond):
$exec /var/web/the_gelatospot/mez_server.sh
Cela n'a pas (/etc/init/site_service.conf):
description "mez sites virtualenv and uwsgi_Django" start on runlevel
[2345] stop on runlevel [06] respawn respawn limit 10 5 exec
/var/web/the_gelatospot/mez_server.sh
Le processus commencerait mais à chaque demande, nginx se plaindrait de la connexion fermée. Bizarrement, cette même configuration fonctionne parfaitement pour 2 autres applications utilisant la même version de nginx et la même version de uwsgi, de même que les deux applications, sont des applications de type mezzanine CMS. J'ai essayé tout ce que je pouvais penser et ce qui était suggéré. En fin de compte je suis passé à gunicorn qui fonctionne bien:
#!/bin/bash
NAME="the_gelatospot" # Name of the application
DJANGODIR=/var/web/the_gelatospot # Django project directory
SOCKFILE=/var/web/the_gelatospot/gunicorn.sock # we will communicte using this unix socket
USER=ec2-user
GROUP=ec2-user # the user to run as, the group to run as
NUM_WORKERS=3 # how many worker processes should Gunicorn spawn
Django_SETTINGS_MODULE=settings
#Django_SETTINGS_MODULE=the_gelatospot.settings # which settings file should Django use
#Django_WSGI_MODULE=the_gelatospot.wsgi # WSGI module name
Django_WSGI_MODULE=wsgi
echo "Starting $NAME as `the_gelatospot`"
# Activate the virtual environment
cd $DJANGODIR
source ../mez_env/bin/activate
export Django_SETTINGS_MODULE=$Django_SETTINGS_MODULE
export PYTHONPATH=$DJANGODIR:$PYTHONPATH
# Create the run directory if it doesn't exist
RUNDIR=$(dirname $SOCKFILE)
test -d $RUNDIR || mkdir -p $RUNDIR
cd ..
# Start your Django GUnicorn
# Programs meant to be run under supervisor should not daemonize themselves (do not use --daemon)
exec gunicorn -k eventlet ${Django_WSGI_MODULE}:application \
--name $NAME \
--workers $NUM_WORKERS \
--log-level=debug \
--bind=unix:$SOCKFILE
Et voici celui qui ne fonctionnerait pas en tant que service (nginx se plaint d’une connexion prématurément fermée et de l’absence de données du journal des applications).
#!/bin/bash
DJANGODIR=/var/web/the_gelatospot/ # Django project directory
cd $DJANGODIR
source ../mez_env/bin/activate
uwsgi --ini uwsgi.ini
Et le uwsgi.ini:
[uwsgi]
uid = 222
gid = 500
socket = /var/web/the_gelatospot/uwsgi.sock
virtualenv = /var/web/mez_env
chdir = /var/web/the_gelatospot/
wsgi-file = /var/web/the_gelatospot/wsgi.py
pythonpath = ..
env = Django_SETTINGS_MODULE=the_gelatospot.settings
die-on-term = true
master = true
chmod-socket = 666
;experiment using uwsgitop
worker = 1
;gevent = 100
processes = 1
daemonize = /var/log/nginx/uwsgi.log
logto = /var/log/nginx/uwsgi.logi
log-maxsize = 10000000
enable-threads = true
Je suis passé de gunicorn à uWSGI l’année dernière et je n’avais aucun problème avec cela jusqu’à présent, cela semblait aussi un peu plus rapide que gunicorn. En ce moment je pense à coller au gunicorn. Cela s'améliore, affiche de meilleurs chiffres avec Eventlet installé et est plus facile à configurer.
J'espère que cette solution de contournement aide. Je voudrais toujours connaître le problème avec uWSGI et nginx mais je suis perplexe.
Mise à jour: Donc, utiliser gunicorn m'a permis de faire fonctionner le serveur en tant que service et, alors que je jouais en mezzanine, j'ai rencontré cette erreur: FileSystemEncodingChanged
Pour résoudre ce problème, j'ai trouvé la solution ici: https://groups.google.com/forum/#!msg/mezzanine-users/bdln_Y99zQw/9HrhNSKFyZsJ
Et j'ai dû le modifier un peu car je n'utilise pas supervisord, je n'utilise que le script upstart et un shell. J'ai ajouté ceci à droite avant d'exécuter gunicorn dans mon fichier mez_server.sh:
export LANG=en_US.UTF-8, LC_ALL=en_US.UTF-8, LC_LANG=en_US.UTF-8
exec gunicorn -k eventlet ${Django_WSGI_MODULE}:application \
--name $NAME \
--workers $NUM_WORKERS \
--log-level=debug \
--bind=unix:$SOCKFILE
J'ai aussi essayé ce correctif en utilisant uWSGI (donc beaucoup plus court depuis l'utilisation de uwsgi.ini):
export LANG=en_US.UTF-8, LC_ALL=en_US.UTF-8, LC_LANG=en_US.UTF-8
exec uwsgi --ini uwsgi.ini
Je m'en tiens toujours à gunicorn car cela a toujours fonctionné avec le problème et m'a conduit dans la bonne direction pour le résoudre. J'ai été très déçu que uWSGI n'ait fourni aucune sortie dans le fichier journal, même avec ces paramètres, j'ai seulement vu le processus de démarrage du serveur et c'est tout:
daemonize = /var/log/nginx/uwsgi.log
logto = /var/log/nginx/uwsgi.logi
Alors que nginx n'arrêtait pas de générer l'erreur de déconnexion, uWSGI restait assis comme si de rien n'était.