Quando o processo recebe SIGTERM
, ele deve ser encerrado e encerrado, com o mínimo de operações possível e sem imprimir nada.
Um processo werkzeug.serving.run_simple
recebendo SIGTERM
geralmente resulta em um código de retorno de 141 (sintoma de um SIGPIPE
não / maltratado), e ao usar o recarregador o processo torna-se zumbi (ele tem para ser eliminado manualmente, pois a porta permanece ligada).
Adicionar um manipulador de sinal para SIGTERM
que simplesmente invoca sys.exit(0)
é suficiente para corrigir o problema (já que não há mais mau comportamento do processo), mas não tenho certeza se é a correção realmente correta.
Eu vinculo um manipulador de sinal agora quando executado com reloader. Espero que ajude.
Em que versão está essa correção? Isso ainda é um problema no Flask 0.8.
Isso ainda é um problema, é bastante irritante quando se usa o Flask com um IDE - sempre que você para de depurar, o processo persiste e continua atendendo às solicitações.
Estou reabrindo este problema porque parece persistir, veja a seguinte discussão do IRC hoje.
20:20 < mcdonc> can somebody fix flask's reloader so when you send the process a sigint it actually stops the child process
20:20 < untitaker> mcdonc: it seems to work for me
20:21 < untitaker> mcdonc: it used to cause problems but for me it's fixed in latest master
20:21 < mcdonc> ah good. i just got some number of complaints from people who run it under supervisor.
20:22 < untitaker> mcdonc: you are talking about the one from the Py3 port?
20:22 < untitaker> released versions should work properly
20:22 < mcdonc> no.. i am talking about.. well.. yes, i dont actually know what i'm talking about ;-) i dont use it, i just get people telling me they need to send a stop signal to the entire process group instead of to the process to make sure its killed.
20:23 < mcdonc> this is not recent.. for the last year or so
20:23 < mcdonc> why people run the reloader under supervisor (presumably in production) i cannot fathom
20:23 < mcdonc> but they do
20:24 < Alex_Gaynor> mcdonc: I've toyed with using supervisord in dev, FWIW
20:24 < Alex_Gaynor> mcdonc: for cases where you don't just have web proc, you've also got background daemons and such, it could be nice
[...]
20:32 < DasIch> untitaker: the supervisor issue is independent from the threading/thread issue
20:32 < untitaker> DasIch: ah okay
20:32 < untitaker> didn't know that
20:32 < untitaker> DasIch: is the reloader behaving weird in supervisor?
20:33 < DasIch> untitaker: I guess what happens if you run the reloader in supervisor is that supervisor kill the reloading process but that doesn't kill the process started by the reloader
20:34 < untitaker> DasIch: couldn't one write a wrapper shell script that kills both?
20:34 < untitaker> at least for now
20:34 < DasIch> untitaker: I think you shouldn't use the reloader in production
20:35 < untitaker> well yeah
20:35 < asdf`> (supervisord has a 'kill as group' thing)
20:35 < DasIch> right there is that as well
20:35 < asdf`> (it even mentions the werkzeug reloader in the docs paragraph about it!)
20:36 < mcdonc> yes i put it there
20:37 < asdf`> (then you might want to fix it, because AFAIR it actually says 'flask', while the reloader is part of werkzeug. But i admit 'flask' is something more people will know)
20:37 < mcdonc> nobody reads docs anyway ;)
20:38 < DasIch> I just wanted to mention I don't care unless someone creates an issue with a valid use case for that but apparently this seems to be it https://github.com/mitsuhiko/werkzeug/issues/58
20:38 < mcdonc> like alex said, it's not entirely crazy to want to use the reloader under supervisor in dev, esp. if your app is reliant on other processes being started
20:39 < mcdonc> i actually dont run my own apps under supervisor, but that's because i don't use a reloader, i just press ctrl-c.. because i'm a savage
20:40 < DasIch> I do use the reloader but I tend to save so often with bad syntax that I end up restarting manually all the time
Acho que ainda é relevante.
Fazer os.kill(parent_id, signal.SIGTERM)
não mata os processos filhos.
Também encontrei esse problema ao refazer a suíte de teste para werkzeug.serving
. Eu contornei isso eliminando todo o grupo de processos: https://github.com/mitsuhiko/werkzeug/blob/a00377315bbf02ec48fdad22c6bb08433fc1e9c1/tests/conftest.py#L158
Corri para este mesmo problema no Flask com modo de depuração (use_debugger = True). No entanto, vejo um código de retorno de 0 no processo "pai". Sem o modo de depuração habilitado, SIGTERM funciona bem e o processo sai com o código 143. Python 2.7.5.
Também fui atingido por esse bug, no meu caso docker stop
estava enviando SIGTERM
para o servidor movido a werkzeug (moto), mas o servidor ignorou e o docker o matou com SIGKILL
resultante em um código de saída diferente de zero.
A solução alternativa foi especificar SIGINT
(Ctrl + C) como um sinal de parada preferencial no Dockerfile ( STOPSIGNAL SIGINT
), depois que os contêineres foram encerrados de forma limpa.
Eu tenho o mesmo problema ao executar um aplicativo Flask dentro do Docker; entretanto, STOPSIGNAL SIGINT
ainda não é suficiente para parar o contêiner. Tenho que usar SIGKILL
.
Não consigo recriar o problema. Eu tentei isso com o contêiner Python oficial com a tag 2.7 e 3.7. Usei o seguinte Dockerfile:
FROM python:2.7
WORKDIR /usr/src/app
RUN pip install click \
werkzeug \
sqlalchemy \
jinja2
COPY . .
RUN python manage-shorty.py initdb
ENTRYPOINT ["python"]
CMD ["manage-shorty.py", "runserver"]
E construiu um contêiner do Dockerfile no diretório examples
com o comando:
docker build -t werkzeug-examples .
Em seguida, executaria o contêiner no modo interativo e cancelaria com:
$ docker run -it --name werkzeug-example werkzeug-examples
* Running on http://localhost:5000/ (Press CTRL+C to quit)
* Restarting with stat
^C
A execução de docker ps
mostrou que ele saiu com 0
:
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
8c708ea4ef77 werkzeug-examples "python manage-short…" About a minute ago Exited (0) 58 seconds ago werkzeug-example
Executar o contêiner e parar com docker stop werkzeug-example
também sai com 0
.
Aqui está o resultado da versão do Docker no computador em que executei estes comandos:
Client: Docker Engine - Community
Version: 18.09.2
API version: 1.39
Go version: go1.10.8
Git commit: 6247962
Built: Sun Feb 10 04:12:39 2019
OS/Arch: darwin/amd64
Experimental: false
Server: Docker Engine - Community
Engine:
Version: 18.09.2
API version: 1.39 (minimum version 1.12)
Go version: go1.10.6
Git commit: 6247962
Built: Sun Feb 10 04:13:06 2019
OS/Arch: linux/amd64
Experimental: false
Você pode fornecer um exemplo que reproduza o problema que você está enfrentando?
Até que possamos obter um cenário reproduzível, fecharei isso, pois não pode ser reproduzido na versão mais recente do Docker e do Werkzeug.
Comentários muito úteis
Também fui atingido por esse bug, no meu caso
docker stop
estava enviandoSIGTERM
para o servidor movido a werkzeug (moto), mas o servidor ignorou e o docker o matou comSIGKILL
resultante em um código de saída diferente de zero.A solução alternativa foi especificar
SIGINT
(Ctrl + C) como um sinal de parada preferencial no Dockerfile (STOPSIGNAL SIGINT
), depois que os contêineres foram encerrados de forma limpa.