UWSGI работает как процесс, но не как демон
Для моего текущего развертывания фляг мне пришлось настроить сервер uwsgi.
Вот как я создал демон 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
Однако после успешного выполнения этого действия: sudo start uwsgi
uwsgi start/running, process 1286
И попытка доступа к приложению через браузер:
Я получаю 502 Bad Gateway
и запись ошибки в nginx error.log:
2013/06/13 23:47:28 [error] 743 # 0: * 296 вверх по течению преждевременно закрыто соединение при чтении заголовка ответа вверх, клиент: xx.161.xx.228, сервер: myproject.com, запрос: "GET/show_records/2013/6 HTTP/1.1", вверх по течению: msgstr "uwsgi://unix:///tmp/uwsgi.sock:", host: "myproject.com"
Но файл sock имеет необходимое ему разрешение:
srw-rw-rw- 1 www-data www-data 0 Jun 13 23:46 /tmp/uwsgi.sock
Если я запускаю команду exec
сверху в командной строке в качестве процесса, она отлично работает. Почему демон работает неправильно?
btw Nginx работает как
vim /etc/nginx/nginx.conf
user www-data;
и vim /etc/nginx/sites-available/default
location / {
uwsgi_pass unix:///tmp/uwsgi.sock;
include uwsgi_params;
}
и он запускается как sudo service nginx start
Я запускаю это на Ubuntu 12.04 LTS
.
Надеюсь, что я предоставил все необходимые данные, надеюсь, что кто-то поможет мне в правильном направлении. Спасибо.
Ответы
Ответ 1
Наконец, я решил эту проблему после работы на ней почти 2 дня. Я надеюсь, что это решение поможет другим пользователям flask/uwsgi, которые испытывают аналогичную проблему.
У меня были две основные проблемы, вызвавшие это.
1). Лучший способ найти проблемы с демоном - это, очевидно, файл журнала и более чистая структура.
sudo vim /etc/init/uwsgi.conf
Измените демона script на следующее:
# 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
Это намного более простой способ настройки демона. Также обратите внимание на последнюю строку, как настроить файл журнала. Первоначально я установил файл журнала в /var/log/uwsgi/error.log
. После много пота и слез я понял, что демон работает как www-data
и, следовательно, не может получить доступ к /var/log/uwsgi/error.log
, поскольку error.log принадлежит root:root
. Это заставило uwsgi терпеть неудачу молча.
Я нашел гораздо более эффективным просто указать файл журнала на свой собственный /myproject
, где у демона есть гарантированный доступ как www-data
. Кроме того, не забудьте сделать весь проект доступным для www-data
, или демон будет терпеть неудачу с Internal Server error message
. →
sudo chown www-data:www-data -R /myproject/
Перезапустите демон uwsgi:
sudo service uwsgi restart
2) Теперь у вас есть три файла журнала для поиска:
-
tail -f /var/log/upstart/uwsgi.log
→ Показывает проблемы с вашим демоном при запуске
-
tail -f /var/log/nginx/error.log
→ Показывает проблемы с разрешениями при отказе доступа wsgi, часто потому, что /tmp/uwsgi.sock
файл принадлежит root
вместо www-data
. В этом случае просто удалите файл sock sudo rm /tmp/uwsgi.sock
-
tail -f /myproject/error.log
→ Показывает ошибки, вызванные uwsgi в вашем приложении
Эта комбинация файлов журналов помогла мне понять, что у меня также был плохой импорт с Flask-Babel в моем приложении Flask. Плохо в этом смысле, что способ, которым я использовал библиотеку, возвращался к языку системы, чтобы определить формат даты и времени.
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'
Именно так я использовал фильтр 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))
Самая странная часть заключается в том, что этот код отлично работает в среде dev (!). Он работает даже отлично при запуске uwsgi в качестве корневого процесса из командной строки. Но это не удается при запуске демоном www-data. Это должно иметь какое-то отношение к тому, как установлен языковой стандарт, к которому Flask-Babel пытается вернуться.
Когда я изменил импорт, как это, все закончилось с демоном:
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))
Поэтому будьте осторожны при использовании Eclipse/Aptana Studio, которая пытается выбрать правильное пространство имен для ваших классов в коде. Это действительно может стать уродливым.
Теперь он отлично работает как демон uwsgi на Amazon Ec2 (Ubuntu 12.04) с 2 дней. Надеюсь, этот опыт поможет разработчикам python.
Ответ 2
Я сдался, не было никакого uwsgi.log, и nginx просто жаловался:
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"
для каждого отдельного запроса. Это произошло только при запуске uwsgi в качестве сервиса, так как процесс был запущен под любым пользователем. Таким образом, это будет работать из командной строки (страница отвечает):
$exec /var/web/the_gelatospot/mez_server.sh
Это не (/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
Процесс начнется, но по каждому запросу nginx будет жаловаться на закрытое соединение. Как ни странно, у меня есть такая же конфигурация, которая отлично подходит для 2 других приложений, использующих ту же версию nginx и такую же uwsgi-версию, что и оба приложения - это мезонинные приложения CMS. Я пробовал все, что мог придумать, и что было предложено. В итоге я переключился на пулемет, который отлично работает:
#!/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
И вот тот, который не будет работать как услуга (nginx жалуется на преждевременно закрытое соединение и не поступает данных журнала приложения).
#!/bin/bash
DJANGODIR=/var/web/the_gelatospot/ # Django project directory
cd $DJANGODIR
source ../mez_env/bin/activate
uwsgi --ini uwsgi.ini
И 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
В прошлом году я пошел от gunicorn к uWSGI, и до сих пор у меня не было никаких проблем с ним, это также показалось немного быстрее, чем ублюдок. Прямо сейчас я думаю о том, чтобы придерживаться пушки. Он становится лучше, выделяет гораздо более удобные номера с установленным флажком, и его легче настроить.
Надеемся, что это обходное решение поможет. Я все еще хотел бы знать проблему с uWSGI и nginx, но я в тупике.
Update:
Таким образом, использование gunicorn позволило мне запустить сервер в качестве службы, а во время игры в мезонине я столкнулся с этой ошибкой: FileSystemEncodingChanged
Чтобы исправить это, я нашел решение здесь:
https://groups.google.com/forum/#!msg/mezzanine-users/bdln_Y99zQw/9HrhNSKFyZsJ
И мне пришлось немного изменить его, так как я не использую supervisord, я использую только выскочку и оболочку script. Я добавил это прямо перед тем, как выполнить gunicorn в файле 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
Я также испробовал это исправление, используя uWSGI, как это (намного короче с использованием 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
Я все еще придерживаюсь оружия, так как он все еще работает с проблемой и ведет меня в правильном направлении, чтобы разрешить это. Я был очень разочарован тем, что uWSGI не предоставил результат в файле журнала даже с этими параметрами, я только видел процесс запуска сервера и что он:
daemonize = /var/log/nginx/uwsgi.log
logto = /var/log/nginx/uwsgi.logi
В то время как nginx продолжал бросать ошибку разъединения, uWSGI сидел там, как ничего не происходит.
Ответ 3
Как одна строка, работающая с командой daemon true, -
gunicorn app.wsgi:application -b 127.0.0.1:8000 --daemon
свяжите ваше приложение с 127.0.0.1:8000 и --deamon запустите его для запуска в качестве демона
но определить файл gunicorn_config.cfg и запустить с флагом -c - хорошая практика
для более:
https://gunicorn-docs.readthedocs.org/en/develop/configure.html