Не удалось запустить процесс из bash-скрипта
У меня есть центральный сервер, где я периодически запускаю скрипт (из cron), который проверяет удаленные серверы. Проверка выполняется последовательно, поэтому сначала один сервер, а затем другой....
Этот скрипт (с центрального сервера) запускает другой скрипт (назовем его update.sh) на удаленной машине, и этот скрипт (на удаленной машине) выполняет что-то вроде этого:
processID=`pgrep "processName"`
kill $processID
startProcess.sh
Процесс убивается и затем в скрипте startProcess.sh запускается так:
pidof "processName"
if [ ! $? -eq 0 ]; then
nohup "processName" "processArgs" >> "processLog" &
pidof "processName"
if [! $? -eq 0]; then
echo "Error: failed to start process"
...
Update.sh, startprocess.sh и фактический двоичный файл процесса, который он запускает, находятся на NFS, смонтированной с центрального сервера.
Что иногда происходит, так это то, что процесс, который я пытаюсь запустить в файле startprocess.sh, не запускается, и я получаю сообщение об ошибке. Странно то, что это случайный процесс: иногда процесс на одной машине запускается, а другой раз на той же машине не запускается. Я проверяю около 300 серверов, и ошибки всегда случайны.
Другое дело, что удаленные серверы находятся в 3 разных географических точках (2 в Америке и 1 в Европе), центральный сервер находится в Европе. Из того, что я обнаружил, является то, что на серверах в Америке гораздо больше ошибок, чем в Европе.
Сначала я подумал, что ошибка связана с kill, поэтому я добавил сон между kill и startprocess.sh, но это не имело никакого значения.
Также кажется, что процесс из startprocess.sh вообще не запускается, или что-то происходит с ним прямо при запуске, потому что в лог-файле нет выходных данных, а в лог-файле должен быть выход.
Итак, здесь я прошу о помощи
У кого-нибудь была такая проблема, или знаете, что может быть не так?
Спасибо за любую помощь
1 ответ
(Извините, но мой первоначальный ответ был довольно неправильным... Вот исправление)
С помощью $?
чтобы получить статус выхода фонового процесса в startProcess.sh
приводит к неверному результату. Ман Баш говорит:
Special Parameters
? Expands to the status of the most recently executed foreground
pipeline.
Как вы упомянули в своем комментарии, правильным способом получения статуса завершения фонового процесса является использование wait
встроенный. Но для этого bash должен обрабатывать сигнал SIGCHLD.
Я сделал небольшую тестовую среду для этого, чтобы показать, как она может работать:
Вот скрипт loop.sh
запустить в качестве фонового процесса:
#!/bin/bash
[ "$1" == -x ] && exit 1;
cnt=${1:-500}
while ((++c<=cnt)); do echo "SLEEPING [$$]: $c/$cnt"; sleep 5; done
Если аргумент -x
затем он выходит со статусом выхода 1 для имитации ошибки. Если значение arg равно num, то ожидается печать num*5 секунд. SLEEPING [<PID>] <counter>/<max_counter>
на стандартный вывод
Второй сценарий запуска. Начинается 3 loop.sh
скрипты в фоновом режиме и распечатывает их статус выхода:
#!/bin/bash
handle_chld() {
local tmp=()
for i in ${!pids[@]}; do
if [ ! -d /proc/${pids[i]} ]; then
wait ${pids[i]}
echo "Stopped ${pids[i]}; exit code: $?"
unset pids[i]
fi
done
}
set -o monitor
trap "handle_chld" CHLD
# Start background processes
./loop.sh 3 &
pids+=($!)
./loop.sh 2 &
pids+=($!)
./loop.sh -x &
pids+=($!)
# Wait until all background processes are stopped
while [ ${#pids[@]} -gt 0 ]; do echo "WAITING FOR: ${pids[@]}"; sleep 2; done
echo STOPPED
Функция handle_chld будет обрабатывать сигналы SIGCHLD. Настройка параметра monitor
позволяет неинтерактивному сценарию получать SIGCHLD. Затем ловушка устанавливается для сигнала SIGCHLD.
Затем запускаются фоновые процессы. Все их PID запоминаются в pids
массив. Если получен SIGCHLD, то среди каталогов /proc/ проверяется, какой дочерний процесс был остановлен (отсутствующий) (это также можно проверить с помощью kill -0 <PID>
Баш встроен). После ожидания состояние выхода фонового процесса сохраняется в известной $?
псевдопеременная.
Основной скрипт ожидает остановки всех pids (в противном случае он не может получить статус выхода своих дочерних элементов) и останавливается сам.
Пример вывода:
WAITING FOR: 13102 13103 13104
SLEEPING [13103]: 1/2
SLEEPING [13102]: 1/3
Stopped 13104; exit code: 1
WAITING FOR: 13102 13103
WAITING FOR: 13102 13103
SLEEPING [13103]: 2/2
SLEEPING [13102]: 2/3
WAITING FOR: 13102 13103
WAITING FOR: 13102 13103
SLEEPING [13102]: 3/3
Stopped 13103; exit code: 0
WAITING FOR: 13102
WAITING FOR: 13102
WAITING FOR: 13102
Stopped 13102; exit code: 0
STOPPED
Видно, что коды выхода сообщаются правильно.
Я надеюсь, что это может немного помочь!