Не удалось запустить процесс из 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

Видно, что коды выхода сообщаются правильно.

Я надеюсь, что это может немного помочь!

Другие вопросы по тегам