Em que ordem devo enviar sinais para processos de desligamento normal?

Em um comentário sobre essa resposta de outra pergunta , o comentarista diz:

não use kill -9 a menos que seja absolutamente necessário! SIGKILL não pode ser preso, então o programa morto não pode executar nenhuma rotina de desligamento para, por exemplo, apagar arquivos temporários. Primeiro tente HUP (1), depois INT (2), então QUIT (3)

Concordo em princípio sobre o SIGKILL , mas o resto é novidade para mim. Dado que o sinal padrão enviado pelo kill é SIGTERM , eu esperaria que fosse o sinal mais esperado para o desligamento normal de um processo arbitrário. Além disso, tenho visto o SIGHUP usado por razões que não terminam, como dizer a um daemon “reler seu arquivo de configuração”. E parece-me que o SIGINT (a mesma interrupção que normalmente se obtém com o Ctrl-C, certo?) Não é tão amplamente suportado como deveria ser, ou termina de forma desagradável.

Dado que o SIGKILL é um último recurso – Que sinais, e em que ordem , você deve enviar para um processo arbitrário, a fim de desligá-lo da forma mais elegante possível?

Por favor, substancie suas respostas com fatos de apoio (além da preferência ou opinião pessoal) ou referências, se puder.

Nota: Estou particularmente interessado nas práticas recomendadas que incluem a consideração do bash / Cygwin.

Edit: Até agora, ninguém parece mencionar INT ou QUIT, e há uma menção limitada do HUP. Existe alguma razão para incluí-los em uma matança de processo ordenada?

SIGTERM informa um aplicativo para finalizar. Os outros sinais informam ao aplicativo outras coisas que não estão relacionadas ao desligamento, mas às vezes podem ter o mesmo resultado. Não use isso. Se você quiser que um aplicativo seja desligado, informe-o. Não dê sinais enganosos.

Algumas pessoas acreditam que a maneira padrão inteligente de encerrar um processo é enviando uma série de sinais, como HUP, INT, TERM e KILL. Isto é ridículo. O sinal certo para a terminação é SIGTERM e se o SIGTERM não encerrar o processo instantaneamente, como você preferiria, é porque o aplicativo escolheu controlar o sinal. O que significa que tem uma razão muito boa para não terminar imediatamente: Tem trabalho de limpeza para fazer. Se você interromper esse trabalho de limpeza com outros sinais, não há como dizer quais dados da memory ainda não foram salvos no disco, quais aplicativos clientes ficam pendurados ou se você está interrompendo o “meio da frase”, o que é efetivamente corrupção de dados.

Para mais informações sobre o significado real dos sinais, veja sigaction (2). Não confunda “Ação Padrão” com “Descrição”, eles não são a mesma coisa.

O SIGINT é usado para sinalizar uma “interrupção do teclado” interativa do processo. Alguns programas podem lidar com a situação de uma maneira especial para os usuários do terminal.

O SIGHUP é usado para sinalizar que o terminal desapareceu e não está mais olhando para o processo. Isso é tudo. Alguns processos optam por desligar em resposta, geralmente porque sua operação não faz sentido sem um terminal, alguns optam por fazer outras coisas, como verificar novamente os arquivos de configuração.

SIGKILL é usado para remover o processo com força do kernel. É especial no sentido de que não é realmente um sinal para o processo, mas sim interpretado diretamente pelo kernel.

Não envie SIGKILL. SIGKILL certamente nunca deve ser enviado por scripts. Se o aplicativo manuseia o SIGTERM, ele pode levar um segundo para a limpeza, pode levar um minuto, pode levar uma hora . Dependendo do que o aplicativo precisa ser feito antes de estar pronto para terminar. Qualquer lógica que ” assuma ” que a sequência de limpeza de um aplicativo demore o suficiente e precise ser um atalho ou SIGKILLed após X segundos é simplesmente errada .

A única razão pela qual um aplicativo precisaria de um SIGKILL para terminar, é se algo estiver errado durante a sequência de limpeza. Nesse caso, você pode abrir um terminal e SIGKILL manualmente. Afora isso, a única outra razão pela qual você SIGKILL algo é porque você quer evitar que se limpe-se.

Embora metade do mundo envie cegamente o SIGKILL depois de 5 segundos, ainda é uma coisa terrivelmente errada.

Normalmente você envia SIGTERM , o padrão de kill. É o padrão por um motivo. Somente se um programa não for desligado em um período de tempo razoável, você deve recorrer ao SIGKILL . Mas note que com o SIGKILL o programa não tem possibilidade de limpar coisas e os dados podem estar corrompidos.

Quanto a SIGHUP , o HUP significa “desligar” e, historicamente, significa que o modem foi desconectado. É essencialmente equivalente ao SIGTERM . O motivo pelo qual os daemons às vezes usam SIGHUP para reiniciar ou recarregar config é que os daemons se desconectam de qualquer terminal de controle, pois um daemon não precisa deles e, portanto, nunca receberiam SIGHUP , então esse sinal era considerado “liberado” para uso geral. Nem todos os daemons usam isso para recarregar! A ação padrão para SIGHUP é terminar e muitos daemons se comportam dessa maneira! Então você não pode ir cegamente enviar SIGHUP para daemons e esperar que eles sobrevivam.

Edit: SIGINT é provavelmente inadequado para finalizar um processo, como é normalmente ligado a ^C ou qualquer que seja a configuração do terminal para interromper um programa. Muitos programas capturam isso para seus próprios propósitos, então é comum que não funcione. SIGQUIT normalmente tem o padrão de criar um dump principal, e, a menos que você queira que os arquivos principais SIGQUIT também não é um bom candidato.

Resumo: se você enviar SIGTERM e o programa não morrer dentro do seu prazo, envie-o para SIGKILL .

Resposta curta : Enviar SIGTERM , 30 segundos depois, SIGKILL . Ou seja, enviar SIGTERM , esperar um pouco (pode variar de programa para programa, você pode conhecer melhor o seu sistema, mas 5 a 30 segundos é o suficiente. Ao desligar uma máquina, você pode vê-lo automaticamente esperando até 1’30s Por que a pressa, afinal?), Então envie SIGKILL .

Resposta razoável : SIGTERM , SIGINT , SIGKILL Isso é mais que suficiente. O processo provavelmente terminará antes do SIGKILL .

Longa resposta : SIGTERM , SIGINT , SIGQUIT , SIGABRT , SIGKILL

Isso é desnecessário, mas pelo menos você não está enganando o processo em relação à sua mensagem. Todos esses sinais significam que você quer que o processo pare o que está fazendo e saia.

Não importa qual resposta você escolha desta explicação, tenha isso em mente!

Se você enviar um sinal que significa outra coisa, o processo pode lidar com isso de maneiras muito diferentes (por um lado). Por outro lado, se o processo não lidar com o sinal, não importa o que você enviar, afinal, o processo será encerrado de qualquer maneira (quando a ação padrão for terminar, é claro).

Então, você deve pensar como um programador. Você codificaria um manipulador de funções para, digamos, SIGHUP para encerrar um programa que se conecta com algo ou faria um loop para tentar se conectar novamente? Essa é a questão principal aqui! É por isso que é importante apenas enviar sinais que signifiquem o que você pretende.

Resposta longa quase estúpida :

A tabela abaixo contém os sinais relevantes e as ações padrão, caso o programa não as manipule.

Eu pedi-lhes na ordem que eu sugiro usar (BTW, eu sugiro que você use a resposta razoável , não este aqui), se você realmente precisa experimentá-los todos (seria divertido dizer que a tabela é ordenada em termos de a destruição que eles podem causar, mas isso não é completamente verdade).

Os sinais com um asterisco (*) NÃO são recomendados. O importante é que você nunca saiba o que está programado para fazer. Especialmente SIGUSR ! Pode iniciar o apocalipse (é um sinal livre para um programador fazer o que ele quiser!). Mas, se não for tratado OU no caso improvável de ser tratado para terminar, o programa terminará.

Na tabela, os sinais com opções padrão para finalizar e gerar um core dump são deixados no final, pouco antes do SIGKILL .

 Signal Value Action Comment ---------------------------------------------------------------------- SIGTERM 15 Term Termination signal SIGINT 2 Term Famous CONTROL+C interrupt from keyboard SIGHUP 1 Term Disconnected terminal or parent died SIGPIPE 13 Term Broken pipe SIGALRM(*) 14 Term Timer signal from alarm SIGUSR2(*) 12 Term User-defined signal 2 SIGUSR1(*) 10 Term User-defined signal 1 SIGQUIT 3 Core CONTRL+\ or quit from keyboard SIGABRT 6 Core Abort signal from abort(3) SIGSEGV 11 Core Invalid memory reference SIGILL 4 Core Illegal Instruction SIGFPE 8 Core Floating point exception SIGKILL 9 Term Kill signal 

Então eu sugiro para esta resposta longa e quase estúpida : SIGTERM , SIGINT , SIGHUP , SIGPIPE , SIGQUIT , SIGABRT , SIGKILL

E finalmente, o

Definitivamente estúpida longa resposta longa :

Não tente isto em casa.

SIGTERM , SIGINT , SIGHUP , SIGPIPE , SIGALRM , SIGUSR2 , SIGUSR1 , SIGQUIT , SIGABRT , SIGSEGV , SIGILL , SIGFPE e se nada funcionou, SIGKILL .

SIGUSR2 deve ser tentado antes do SIGUSR1 porque é melhor que o programa não manipule o sinal. E é muito mais provável que ele manipule o SIGUSR1 se ele lidar com apenas um deles.

BTW, o KILL : não é errado enviar o SIGKILL para um processo, como outra resposta afirmou. Bem, pense o que acontece quando você envia um comando de shutdown ? Ele tentará apenas o SIGTERM e o SIGKILL . Por que você acha que é esse o caso? E por que você precisa de outros sinais, se o comando very shutdown usa apenas esses dois?


Agora, de volta à resposta longa , este é um bom oneliner:

 for SIG in 15 2 3 6 9 ; do echo $SIG ; echo kill -$SIG $PID || break ; sleep 30 ; done 

Ele dorme por 30 segundos entre os sinais. Por que mais você precisaria de um oneliner ? 😉

Além disso, recomendado: tente com apenas sinais 15 2 9 da resposta razoável .

segurança : remova o segundo echo quando estiver pronto para ir. Eu chamo-lhe meu dry-run para onliners . Sempre use para testar.


Script killgracefully

Na verdade, fiquei tão intrigado com essa questão que decidi criar um pequeno roteiro para fazer exatamente isso. Por favor, sinta-se à vontade para fazer o download (clone) aqui:

Link do GitHub para o repository Killgracefully

SIGTERM significa, na verdade, enviar uma mensagem para o aplicativo: ” você seria tão gentil e cometeria suicídio “. Ele pode ser preso e manipulado pelo aplicativo para executar o código de limpeza e encerramento.

SIGKILL não pode ser preso pelo aplicativo. O aplicativo é morto pelo sistema operacional sem qualquer chance de limpeza.

É típico enviar SIGTERM primeiro, dormir um pouco e depois enviar SIGKILL .

  • SIGTERM é equivalente a “clicar no ‘X'” em uma janela.
  • SIGTERM é o que o Linux usa primeiro, quando está sendo desligado.

HUP soa como lixo para mim. Eu enviaria para obter um daemon para reler sua configuração.

SIGTERM pode ser interceptado; seus daemons podem ter código de limpeza para executar quando receber esse sinal. Você não pode fazer isso por SIGKILL. Assim, com SIGKILL você não está dando ao autor do daemon nenhuma opção.

Mais sobre isso na Wikipedia

Com toda a discussão acontecendo aqui, nenhum código foi oferecido. Aqui está minha opinião:

 #!/bin/bash $pid = 1234 echo "Killing process $pid..." kill $pid waitAttempts=30 for i in $(seq 1 $waitAttempts) do echo "Checking if process is alive (attempt #$i / $waitAttempts)..." sleep 1 if ps -p $pid > /dev/null then echo "Process $pid is still running" else echo "Process $pid has shut down successfully" break fi done if ps -p $pid > /dev/null then echo "Could not shut down process $pid gracefully - killing it forcibly..." kill -SIGKILL $pid fi