Os scripts Bash executados juntos não matam processos em segundo plano

0

Eu tenho vários scripts de shell que funcionam de maneira muito semelhante a esta questão . Cada script ativa algumas tarefas em segundo plano, lembra seus PIDs com $! , faz alguns testes e depois mata os processos em segundo plano.

Meu problema é que eu quero executar um grande número desses tipos de scripts. Se eu os executar manualmente, um por um, eles funcionam bem: ps -a mostra que os processos em segundo plano foram mortos corretamente.

$ ./test_1.sh
$ ./test_2.sh

No entanto, se eu executar os dois em um comando assim:

$ ./test_1.sh; ./test_2.sh

o processo de segundo plano iniciado por test_1.sh falha ao morrer quando o test_2.sh é iniciado. Isso deixa uma porta amarrada à qual test_2.sh precisa se ligar. Portanto, mesmo que test_1.sh emita os comandos kill corretos, test_2.sh falhará se for executado logo após test_1.sh .

Se eu inserir um atraso entre os scripts, não há problema:

$ ./test_1.sh; sleep 1; ./test_2.sh

Presumivelmente, então, há um atraso entre quando kill é emitido e quando o processo realmente morre e libera a porta.

Minhas perguntas são:

  1. O que está acontecendo? Esta plataforma é específica? Estou no Mac OS X. Mas isso não parece ter sido um problema para as pessoas que originalmente escreveram os scripts no Linux.
  2. Existe uma maneira melhor de garantir que os processos em segundo plano sejam eliminados, sem usar sleep entre os scripts?

Para completar, é assim que um dos scripts de teste se parece:

#!/bin/sh

echo "starting up server 1(parent)..."
$JAVA siena.StartServer -port 7000 &
server1=$!
sleep 2

echo "starting up server 2(the first child)..."
$JAVA siena.StartServer -port 2000 -master senp://:7000 > outputs/test.out2 &
server2=$!

echo "starting up server 3(the second child)..."
$JAVA siena.StartServer -port 3000 -master senp://:7000 > outputs/test.out2 &
server3=$!

sleep 5

kill $server1
kill $server2
kill $server3
    
por SigmaX 03.11.2014 / 22:42

1 resposta

1

Você tem que esperar que os processos morram. Geralmente é uma boa idéia esperar entre um SIGTERM e um SIGKILL.

São consideradas maneiras rudes (e, na minha opinião, pouco profissional) para os processos da SIGKILL sem ter feito um desligamento antes. Isso não só pode criar inconsistências, mas também oculta procedimentos de desligamento defeituosos (programas que não fecham em um determinado momento quando solicitados).

Eu usaria algo como:

# Launch your processes...
DEADLINE=1   #seconds to wait
kill $server1 $server2 $server3
sleep $DEADLINE 
if kill -KILL $server1 $server2 $server3
then 
  echo "Warning: at least one process had not finished in $DEADLINE seconds" >&2
  sleep 1   ## Wait for these just-killed processes to actually die and free their ports
fi 

Outra abordagem seria encontrar uma porta livre de dentro do próprio servidor (ligação sem uma porta e de alguma forma se comunicando fora da porta designada). Isso permitiria testes paralelos. Você poderia gravar o número da porta em um arquivo especificado na linha de comando (em vez da porta, você passaria o nome do arquivo), alterando assim o -port 7000 para algo como -port auto -port-file test-port.txt e aguardando a exibição desse arquivo.-master senp://:$(cat test-port.txt).

Outra ideia seria descobrir automaticamente, com base nas informações de netstat -ntl , se as portas necessárias são gratuitas ou não. Em seguida, você pode escolher aguardar ou especificar um novo conjunto de portas disponíveis. As condições de corrida podem muito bem acontecer entre o momento em que você vê uma porta livre e o momento em que realmente se liga, especialmente se seu algoritmo de alocação é determinista e repetível (como usar a primeira porta disponível a partir de 40000). Deixar o sistema operacional escolher uma porta livre é muito mais robusto.

    
por 04.11.2014 / 14:21

Tags