Como configurar o autoreload com Flask + uWSGI?
Pergunta
Estou procurando algo como uWSGI + modo autoreload django para Flask.
Solução
Você pode tentar usar supervisord como um gerente para seu aplicativo Uwsgi.Ele também tem uma função de observação que recarrega automaticamente um processo quando um arquivo ou pasta é "tocado" / modificado.
Você encontrará um bom tutorial aqui: Flask+ NginX + Uwsgi + Supervisord
Outras dicas
Estou executando o uwsgi versão 1.9.5 e a opção
uwsgi --py-autoreload 1
funciona muito bem
Se você estiver configurando uwsgi
com argumentos de comando, passe --py-autoreload=1
:
uwsgi --py-autoreload=1
Se você estiver usando um arquivo .ini
para configurar uwsgi
e usando uwsgi --ini
, adicione o seguinte ao seu arquivo .ini
:
py-autoreload = 1
Para ambiente de desenvolvimento, você pode tentar usar parâmetro --python-autoreload do uwsgi. Olhando o código-fonte, ele pode funcionar apenas no modo encadeado (--enable-threads).
A funcionalidade de recarregamento automático do Flask no modo de desenvolvimento é, na verdade, fornecida pela biblioteca Werkzeug subjacente. O código relevante está em werkzeug/serving.py
- vale a pena dar uma olhada. Mas, basicamente, o aplicativo principal gera o servidor WSGI como um subprocesso que registra cada arquivo .py
ativo uma vez por segundo, procurando por alterações. Se ele encontrar algum, o subprocesso será encerrado e o processo pai o iniciará novamente - na verdade recarregando os chages.
Não há razão para que você não possa implementar uma técnica semelhante na camada do uWSGI. Se não quiser usar um loop de estatísticas, você pode tentar usar os comandos subjacentes de observação de arquivos do sistema operacional. Aparentemente (de acordo com o código de Werkzeug), pyinotify tem bugs, mas talvez Watchdog funciona? Experimente algumas coisas e veja o que acontece.
Em resposta ao comentário, acho que seria muito fácil reimplementar. Com base no exemplo fornecido em seu link, junto com o código de werkzeug/serving.py
:
""" NOTE: _iter_module_files() and check_for_modifications() are both
copied from Werkzeug code. Include appropriate attribution if
actually used in a project. """
import uwsgi
from uwsgidecorators import timer
import sys
import os
def _iter_module_files():
for module in sys.modules.values():
filename = getattr(module, '__file__', None)
if filename:
old = None
while not os.path.isfile(filename):
old = filename
filename = os.path.dirname(filename)
if filename == old:
break
else:
if filename[-4:] in ('.pyc', '.pyo'):
filename = filename[:-1]
yield filename
@timer(3)
def check_for_modifications():
# Function-static variable... you could make this global, or whatever
mtimes = check_for_modifications.mtimes
for filename in _iter_module_files():
try:
mtime = os.stat(filename).st_mtime
except OSError:
continue
old_time = mtimes.get(filename)
if old_time is None:
mtimes[filename] = mtime
continue
elif mtime > old_time:
uwsgi.reload()
return
check_for_modifications.mtimes = {} # init static
Não foi testado, mas deve funcionar.
import gevent.wsgi
import werkzeug.serving
@werkzeug.serving.run_with_reloader
def runServer():
gevent.wsgi.WSGIServer(('', 5000), app).serve_forever()
(Você pode usar um servidor WSGI arbitrário)
Temo que o Flask seja realmente muito básico para ter uma implementação como esta agrupada por padrão.
O recarregamento dinâmico de código em produção geralmente é uma coisa ruim, mas se você estiver preocupado com um ambiente de desenvolvimento, dê uma olhada neste script de shell bash http://aplawrence.com/Unixart/watchdir.html
Apenas altere o intervalo de suspensão para o que for adequado às suas necessidades e substitua o comando echo pelo que você usar para recarregar o uwsgi.Eu executo o uwsgi no modo master e apenas envio um comando killall uwsgi.