<p>werkzeug.serving.run_simple não lida com SIGTERM corretamente</p>

Criado em 9 mai. 2011  ·  11Comentários  ·  Fonte: pallets/werkzeug

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.

bug

Comentários muito úteis

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.

Todos 11 comentários

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.

Esta página foi útil?
0 / 5 - 0 avaliações

Questões relacionadas

d42 picture d42  ·  6Comentários

lepture picture lepture  ·  6Comentários

davidism picture davidism  ·  9Comentários

golf-player picture golf-player  ·  10Comentários

sorenh picture sorenh  ·  4Comentários