Supervisor: Permitir um "comando de parada" personalizado para gerenciar o desligamento normal dos processos

Criado em 6 set. 2012  ·  57Comentários  ·  Fonte: Supervisor/supervisor

Estou tentando usar supervisord para gerenciar instâncias de aplicativos playframework. A estrutura fornece comandos para iniciar e interromper instâncias que permitem que um aplicativo seja encerrado adequadamente e a execução de eventos de ciclo de vida de plug-ins. Um exemplo é o fechamento adequado do índice de pesquisa Lucene, que não pode ser aberto novamente se for encerrado de maneira inadequada, porque um arquivo "write-lock" permanece no diretório do índice.

O que eu consideraria uma grande adição, seria a possibilidade de especificar algo assim:

[programa: my-play-web-app]
comando = / opt / play-1.2.5 / play start
stop-command = / opt / play-1.2.5 / play stop
diretório = / caminho / para / home-of-play-web-app /

Existe algum meio de fazer isso com o supervisord agora? A única solução alternativa que encontrei é a seguinte:

[programa: my-play-web-app]
comando = / caminho / para // home-of-play-web-app / startup.sh
diretório = / caminho / para / home-of-play-web-app /

Com startup.sh sendo:

trap "{echo Parando app de reprodução; /opt/play-1.2.5/parada de reprodução; sair 0;}" SAIR
echo Iniciando o aplicativo de reprodução
/opt/play-1.2.5/play start

(retirado daqui: http://stackoverflow.com/questions/7732371/how-to-properly-manage-rabbitmq-with-supervisord)

Comentários muito úteis

Cinco anos depois, ainda não havia um "comando de parada" para gerenciar o desligamento normal de processos, o que é uma pena, honestamente.

Todos 57 comentários

Também gostaria de ver isso. Parece ser um problema comum de daemon de java. Não consigo parar minhas instâncias wowza graciosamente.

+1

Acabei de publicar um post que pode fornecer uma solução (para Play2) de como fazer o Play Framework 2 funcionar com Supervisord e Monit . Não tenho certeza se vai funcionar no seu caso

+1

+1

+1

+1

+1

+1

+1

+1

Também gostaria da opção de enviar um comando para o processo diretamente como se estivesse no modo fg .

Então, por exemplo, dado um servidor de jogo que requer um comando /stop para desligar e salvar o servidor de forma limpa, eu gostaria de poder fazer o seguinte em meu arquivo de configuração:

[program:my-awesome-server]
command=/some/dir/start-awesome-server.sh
fg-stop-command=/stop

onde /stop é o comando que eu normalmente inseriria manualmente enquanto em supervisorctl fg <process>

+1

+1

+1
Há algum motivo para que isso ainda não tenha sido resolvido?

Provavelmente porque ninguém fez isso. Tenho certeza de que eles aceitam solicitações pull.

1 com certeza.

+1
seria muito útil quando o supervisor precisa gerenciar os contêineres do docker e eles são iniciados usando o script bash, portanto, o envio de um sinal de eliminação para o processo do bash não para o contêiner do docker

+1

+1

Para melhor ou pior, o supervisor requer que os processos iniciados permaneçam filhos diretos do processo supervisord (ver http://supervisord.org/subprocess.html#nondaemonizing-of-subprocesses), e que o envio de algum sinal para esse processo filho irá pare de forma limpa. Você pode especificar _which_ o supervisor de sinal deve enviar para encerrar o processo de forma limpa (consulte stopsignal em http://supervisord.org/configuration.html#program-x-section-settings), mas suportando um modelo totalmente diferente para interromper um processo do que enviar um processo filho direto de um sinal está fora do escopo do Supervisor. Como resultado, a solução alternativa na postagem original do problema é "correta" (o programa bash que, neste caso, atua como uma espécie de proxy, usando trap para lidar com o sinal) para alguma definição de correto. Pode haver uma maneira "mais correta" de iniciar o programa ( play neste caso), que iniciaria o programa de tal forma que o envio de um sinal como o SIGTERM permitiria que ele desligasse de forma limpa ( conforme descrito em http://blog.fgribreau.com/2013/09/how-to-make-play-framework-2-work-with.html vinculado por @FGRibreau acima), mas a solução alternativa é razoável se houver 't.

Por isso, devo encerrar este problema. Há uma chance quase zero de o supervisor oferecer suporte a um mecanismo diferente para sinalizar a um programa que ele deve ser encerrado, exceto o envio de um sinal UNIX real para um processo filho direto.

Minha opinião pessoal, que influencia o acima: se o programa não pode ser encerrado normalmente usando um sinal UNIX, ele está possivelmente quebrado, já que comandos comuns como "kill" também não funcionarão contra ele. E isso não é muito lógico.

+1

Obrigado pela excelente explicação de por que funciona assim. O comando "stop" geralmente apenas organiza um desligamento normal e executa alguns ganchos de desligamento de nível de aplicativo e código de usuário. Se isso estiver sendo feito apenas para enviar um sinal ao processo, concordo que não há necessidade de alteração.

No entanto, pode haver muitos outros programas que não fazem isso e que as pessoas podem querer executar com o supervisor. Em vez de alterar o mecanismo de processo do supervisor, seria viável ter um comando de "pré-desligamento"? Em vez de ter o controle personalizado do procedimento de parada e tirar esse controle do supervisor, é apenas um meio de reagir a esse evento, assumindo que o programa do usuário não manipula corretamente o sinal unix.

Receio que isso também não esteja nas cartas, pois acrescentaria uma boa dose de complexidade ao código de desligamento de processos (executar o comando, registrar sua saída, lidar com um comando que não sai). Desculpa.

Bem, essencialmente, você poderia tratá-lo exatamente como trata o processo real agora. Mas não faz sentido discutir, já que você tem bons motivos pelos quais não é uma boa ideia e eu não estou promovendo um RP, então por que se incomodar. Então, volte para os scripts init.d.

A maneira normal de lidar com essa necessidade é usar um script wrapper em seu daemon, que receberia os sinais do supervisor e emitiria instruções significativas para o daemon subjacente.

Usar algum tipo de comando do vendedor stop que provavelmente depende de um arquivo pid é definitivamente um retrocesso. A melhor maneira de obter o resultado desejado seria enviar 'Ctrl-C' ou 'Ctrl-\' via STDIN conforme descrito em # 555.

+1

+1

+1

+1

Ainda não está claro para mim por que é tão difícil emitir um comando de parada quando um processo supervisionado é interrompido por qualquer motivo. Tenho um exemplo perfeito de por que seria útil:

Tenho um cliente bittorrent Raspberry Pi. Ele apenas fica lá, baixa e semeia vários torrents via Transmission (cliente bittorrent). No entanto, ele também executa o OpenVPN e não quero que ele faça nenhuma atividade relacionada ao torrent, a menos que o OpenVPN esteja em execução e conectado.

Idealmente, eu configuraria o Supervisor para manter o OpenVPN em execução, mas no caso de o OpenVPN alguma vez travar ou o supervisor precisar reiniciá-lo por qualquer motivo, após travar, ele executaria imediatamente o comando bash:

# transmission-remote --torrents all --stop

Para interromper toda a atividade do torrent. E então eu iria iniciá-los novamente assim que o OpenVPN fizesse uma conexão.

Portanto, simplesmente especificar um comando bash para ser executado quando um processo for interrompido ou travado ... seria extremamente útil.

O Systemd suporta um comando de parada personalizado, se você quiser usá-lo.
Em 1º de junho de 2016, 15:56, "Jake Wilson" [email protected] escreveu:

Ainda não está claro para mim por que é tão difícil emitir um comando de parada quando um
o processo supervisionado é interrompido por qualquer motivo. Eu tenho um exemplo perfeito de porque isso
seria útil:

Tenho um cliente bittorrent Raspberry Pi. Ele apenas fica lá e faz o download
e semeia vários torrents via transmissão (cliente bittorrent). Contudo,
ele também roda OpenVPN e eu não quero que ele faça nenhuma atividade relacionada a torrent
a menos que o OpenVPN esteja em execução e conectado.

Idealmente, eu configuraria o Supervisor para manter o OpenVPN em execução, mas no caso
que o OpenVPN já travou ou o supervisor precisou reiniciá-lo para qualquer
razão, depois de travar, ele executaria imediatamente o comando bash:

transmissão-remoto --torrents todos --stop

Para interromper toda a atividade do torrent. E então eu iria iniciá-los
novamente assim que o OpenVPN fizer uma conexão.

Portanto, basta especificar um comando bash para ser executado quando um processo parar ou
travar .... seria extremamente útil.

-
Você está recebendo isto porque está inscrito neste tópico.
Responda a este e-mail diretamente, visualize-o no GitHub
https://github.com/Supervisor/supervisor/issues/147#issuecomment -223149392,
ou silenciar o tópico
https://github.com/notifications/unsubscribe/AABwJydcnmZ8pn8fd5U6F9V1JHooErABks5qHg4YgaJpZM4AJAO7
.

+1

+1

+1

Alguma razão para isso ter sido fechado? Eu não vejo esse recurso ainda.

@shatil leia ^^^^

É apenas uma decisão de design usar sinais e apenas um único processo filho por aplicativo / processo. Isso evita todos os tipos de situações, como bombardeio acidental com processos de eliminação e outros comportamentos inesperados que acontecem no systemd e em metodologias semelhantes. Se o processo que você está executando não lidar com isso, use um script Bash e trap para capturar o sinal e executar um comando personalizado .

Além disso, alguns aplicativos iniciam um processo, geram outro e perdem privilégios. Enviar um sinal kill para aquele iniciado por supervisord não faz nada de útil. Um exemplo brilhante é mysqld_safe no Alpine Linux, que é facilmente interrompido usando mysqladmin shutdown , mas não supervisorctl stop mysqld .

supervisor tem objetivos de design diferentes e é provavelmente uma ferramenta errada para usar com esse tipo de aplicativo. Na verdade, requer que os aplicativos sejam projetados de uma maneira específica, em vez de acomodar tudo no universo. Em vez de forçar o pino quadrado em um buraco redondo, você pode tentar algo como daemontools , runit , systemd , etc.

Isso é uma pena, honestamente. Esse recurso é essencial para qualquer software de gerenciamento de serviço.

Cinco anos depois, ainda não havia um "comando de parada" para gerenciar o desligamento normal de processos, o que é uma pena, honestamente.

+1

Você está pedindo que supervisor seja mais parecido com systemd ou init mas por que você não usa systemd ou init vez disso e sai supervisor sozinho? A ausência do comando de parada é o que torna o supervisor tão incrível. Meu voto é para "nenhum comando de parada nunca"!

A ausência do comando de parada é o que torna o supervisor tão incrível.

Quão?..

Para implementar o comando de parada, é necessário manter o controle do processo pid. Isso geralmente é feito armazenando o arquivo pid em algum lugar do sistema de arquivos. Isso cria pelo menos dois problemas 1) o arquivo pid pode ser excluído (intencionalmente / não intencionalmente / corrupção de fs) 2) o arquivo pid não é excluído após a falha do sistema ou desligamento indelicado (ou seja, evento pull the plug) e outro processo iniciado com o mesmo pid id na reinicialização. São circunstâncias raras, mas experimento tudo isso mais vezes do que esperava.

A única maneira confiável de monitorar o estado do processo é separá-lo de um pai (supervisor) e usar os recursos do kernel para controlar / monitorar o filho.

A abordagem start / stop / pid funciona em 99% dos casos e é adequada para aplicativos genéricos onde as falhas são ocorrências comuns e não são um grande problema. No entanto, existem aplicativos onde 99% não é bom o suficiente. Pense em automação industrial, robôs, controles de carro, controles de vôo, etc.

Existem muito poucas ferramentas que fazem o controle de processos desta forma ( daemontools , runit , systemd , supervisor , inittab , pm2 ), há menos ainda que o façam corretamente e supervisor é um dos melhores. Não suportar mecanismos de controle de processo não confiáveis, ter uma pegada pequena e um design claro é o que diferencia o supervisor do resto e eu quero que continue assim.

Para implementar o comando de parada, é necessário manter o controle do processo pid.

Hm ... não. Para implementar o comando de parada, seria necessário adicioná-lo como uma alternativa opcional à lógica send_signal. O comando de parada personalizado não pode usar pid.

O único problema real é o que fazer se o comando de parada não interromper o processo? Eu sugeriria voltar para SIGKILL aqui.

Ugh ... eu tenho que usar init.d não eu.

+1

+1

tosse
+1

No entanto - trabalho incrível, obrigado por manter este pacote, e eu respeito as decisões de design dos mantenedores.

O engraçado é que o supervisord usa o comando de parada por si só:
https://github.com/Supervisor/initscripts/blob/master/centos-systemd-etcs
:)

Por mais de 3 anos, as pessoas pediram para tornar possível interromper aplicativos com um comando ou script, mas nada mudou. É triste.

@rirmak http://www.lmgtfy.com/?q=bash+handle+signal

O Linux Journal tem uma cópia da pasta.

bash + manuseio + sinal

Supervisor 3.3.0:
sinal de parada
O sinal usado para encerrar o programa quando uma parada é solicitada. Pode ser TERM, HUP, INT, QUIT, KILL, USR1 ou USR2.

+1

Além disso, alguns aplicativos iniciam um processo, geram outro e perdem privilégios. Enviar um sinal kill para aquele iniciado por supervisord não faz nada de útil. Um exemplo brilhante é mysqld_safe no Alpine Linux, que é facilmente interrompido usando mysqladmin shutdown , mas não supervisorctl stop mysqld .

Tive o problema com o supervisor e o mysql. Resolvi isso com este pequeno script bash:

#!/bin/bash

# Start script (that would ordinarily have been entered into supervisor config file)
/usr/bin/mysqld_safe &

# Stop script
stop_script() {
    mysqladmin -u root shutdown
    exit 0
}
# Wait for supervisor to stop script
trap stop_script SIGINT SIGTERM

while true
do
    sleep 1
done

Tenho procurado uma solução para um problema semelhante.

Eu tenho um aplicativo PHP que executa consumidores no RabbitMQ, inicialização com supervisor. Eles são executados no EC2 / docker.
Depois de iniciar uma redução ou reimplantar com o código mais recente, a instância / docker do EC2 é destruída. Quando isso acontece, o supervisor / RabbitMQ não permite que o processo se desconecte como uma conexão / consumidor nas filas às quais está conectado. Portanto, tenho muitos consumidores / conexões órfãos em minhas filas.

Preciso de um desligamento normal para os processos do consumidor, então encontrei uma solução alternativa para ajudar nisso. Eu configurei um script Python no Jenkins para verificar se há destinos de drenagem em um LB. Isso me permite ver as instâncias / dockers que estão sendo destruídas, assim que eu ver, posso executar um comando de parada do supervisor via ssh naquele script para os endereços IP do aws cli.

Este script é executado assim que implanto um novo código e novas instâncias são inicializadas. Mas, com a escala automática, ainda não há uma maneira de executar essas tarefas. Portanto, agora sou forçado a executar um CRON periódico a cada 15 minutos ou mais para verificar os alvos de drenagem. Isso irá capturar a maioria das instâncias / dockers ao serem destruídas pelo escalonamento automático.

Espero que alguém aqui também possa usar isso como uma solução alternativa.

Eu direi a vocês se tenho melhores soluções / soluções alternativas.

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

Questões relacionadas

cachvico picture cachvico  ·  3Comentários

eromoe picture eromoe  ·  3Comentários

AlphaSRE picture AlphaSRE  ·  3Comentários

crybat picture crybat  ·  5Comentários

mnaberez picture mnaberez  ·  4Comentários