Inicie um novo grupo de processos para o código Python (usando o setsid
utilitário) e quaisquer outros processos (incluindo o próprio aplicativo), assim você pode matar todo o grupo de processos, se necessário.
Você pode usar a seguinte construção para fazer isso:
exec 3>&1
pgid=$(exec setsid bash -c 'echo $$; exec >&3-; exec COMMAND...')
onde COMMAND...
é o comando e seus parâmetros que você normalmente iniciaria. Observe que ele está entre aspas simples e que o comando a ser executado deve ser avaliavel como uma string (em oposição a uma expressão de shell normal).
O primeiro redirecionamento, 3>&1
, copia o descritor de saída padrão para o descritor 3. O redirecionamento >&3-
move o descritor 3 para a saída padrão.
O $(...)
executa o ...
e avalia os dados que ele gravou na saída padrão. Acima, lemos a saída padrão na variável do shell pgid
.
O subshell ( ...
) é substituído pelo utilitário setsid
, que executa seu argumento em uma nova sessão (grupo de processos). Aqui, ele executa bash
, que imprime o processo atual PID ( $$
), move a saída padrão original do descritor 3 para trás e se substitui / executa o COMMAND...
desejado.
O shell executará essa linha enquanto o COMMAND...
for executado e só avançará para a próxima linha após a saída de COMMAND...
.
Se o COMMAND...
deixar processos espúrios em execução e você quiser eliminá-los, tudo que você precisa fazer é executar
kill -SIGNAL -$pgid
A questão é qual sinal enviar. KILL
eliminará imediatamente os processos restantes no grupo de processos, por isso é a opção mais simples. No entanto, se os processos se comportarem bem, você poderá pedir que eles saiam enviando-lhes um sinal TERM
. É claro que, às vezes, os processos podem ficar em estado instável, de modo que não reajam a TERM
e precisem ser KILL
ed. Para resolver isso, você pode usar um pequeno loop e ps
para ver se ainda há algum processo:
retries=50
while ((1)); do
# Processes left?
left=$(ps -o pid= -s $pgrp)
[ -n "$left" ] || break
# Ask them to terminate.
kill -TERM $left
# Wait 0.1 seconds.
sleep .1
# Decrement the retry counter.
((--retries > 0)) || break
done
# If there are any processes left in the group,
# send them a KILL signal.
left=$(ps -o pid= -s $pgrp)
[ -n "$left" ] && kill -KILL $left
Observe que as 50 tentativas (0,1 segundo cada) significam que isso espera apenas até 5 segundos antes de enviar um sinal de eliminação. Isso pode não ser um valor adequado, dependendo do aplicativo e do tipo de hardware em execução. Por exemplo, se a máquina for um laptop, e o aplicativo salvar algum histórico ou registros em vários arquivos, e a unidade estiver dormindo no ponto de saída, aumentarei o atraso para talvez 15 a 30 segundos. / p>