У меня есть несколько сценариев оболочки, которые работают очень похоже на этот вопрос. Каждый скрипт запускает несколько фоновых задач, запоминает их PID с $! , делает некоторое тестирование, а затем убивает фоновые процессы.

Моя проблема в том, что я хочу запустить большое количество таких скриптов. Если я запускаю их вручную один за другим, они работают нормально: ps -a показывает, что фоновые процессы были убиты правильно.

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

Тем не менее, если я запускаю их обоих в одной команде, например, так:

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

фоновый процесс, запущенный test_1.sh не может умереть к моменту test_2.sh . Это оставляет порт связанным, к которому нужно привязать test_2.sh . Таким образом, даже если test_1.sh выдает правильные команды kill , test_2.sh вылетает, если он выполняется сразу после test_1.sh .

Если я вставлю задержку между сценариями, нет проблем:

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

Предположительно, тогда существует задержка между моментом kill и фактическим завершением процесса и освобождением порта.

Мои вопросы:

  1. В чем дело? Эта платформа специфична? Я на Mac OS X. Но, похоже, это не было проблемой для людей, которые изначально писали сценарии для Linux.
  2. Есть ли лучший способ убедиться, что фоновые процессы были убиты, без использования sleep между сценариями?


Для полноты вот как выглядит один из тестовых сценариев:

#!/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

1 ответ1

1

Вы должны ждать, пока процессы умрут. Обычно хорошей идеей является ожидание между SIGTERM и SIGKILL.

Это считается грубым (и, на мой взгляд, довольно непрофессиональным) процессом SIGKILL без предварительной корректной остановки. Это может не только создать несоответствия, но и скрыть ошибочные процедуры выключения (программы не закрываются через определенное время по запросу).

Я бы использовал что-то вроде:

# 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 

Другой подход заключается в том, чтобы найти свободный порт изнутри самого сервера (связывание без порта и каким-либо образом связь за пределами назначенного порта). Это позволило бы провести параллельное тестирование. Вы можете записать номер порта в файл, указанный в командной строке (вместо порта вы передадите имя файла), таким образом изменив -port 7000 на что-то вроде -port auto -port-file test-port.txt а затем ожидание появления этого файла и затем -master senp://:$(cat test-port.txt) .

Другая идея состоит в том, чтобы автоматически выяснить, основываясь на информации netstat -ntl , свободны ли необходимые порты или нет. Затем вы можете либо подождать, либо указать новый набор доступных портов. Условия гонки вполне могут возникнуть между моментом, когда вы видите свободный порт и моментом фактического связывания, особенно если ваш алгоритм распределения является детерминистическим и повторяемым (например, при использовании первого доступного порта, начинающегося с 40000). Разрешение операционной системе выбирать свободный порт само по себе намного надежнее.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .