Как отложить перевод процесса в фоновый режим до тех пор, пока он не будет готов к работе в оболочке

У меня есть два процесса: сервер, который должен работать в фоновом режиме, но начинает обслуживать запросы после задержки, и клиент, который должен запускаться, когда сервер готов. Когда сервер готов, он выводит строку, содержащую «Acceptinconnections», на свой stderr (сервер stderr перенаправляется в файл при запуске в фоновом режиме).

Как отложить перевод серверного процесса в фоновый режим, пока сервер не будет готов обслуживать запросы? В качестве альтернативы, как отложить запуск клиента, пока сервер не будет готов?

Язык: сценарий оболочки (или опционально Perl).


Добавлено 2010-05-19 22:34 +0000:

Заранее известно, какой TCP-порт сервер будет прослушивать для запросов.

Примечание: сервер — это веб-сервер (подключаемый модуль с HTTP::Server::PSGI), клиент — это веб-браузер, т.е. рысь.


person Jakub Narębski    schedule 19.05.2010    source источник
comment
Я хотел бы избежать занятого цикла, если это возможно   -  person Jakub Narębski    schedule 20.05.2010


Ответы (4)


У вас может быть цикл while, который продолжает проверять файл журнала сервера на наличие этой строки. grep вернет 1, если совпадений не найдено:

false
while [ $? != 0 ]; do
    grep 'Accepting connections' server.log
done
run-client
person Michael Mrozek    schedule 19.05.2010
comment
блин, мне нравится ответ, хотя я предпочитаю тест и возврат каретки вместо ;. - person hendry; 20.05.2010
comment
@Jakub Ну, если это первое, что выводит сервер, и вы знаете, что файла заранее не существовало, то да - person Michael Mrozek; 20.05.2010
comment
while ! grep 'Accepting connections' server.log >/dev/null 2>&1; do :; done; run-client и sleep не помешали бы. - person Dennis Williamson; 20.05.2010

Используйте цикл while:

while :
do
    if ssh [email protected] -p 1202 echo > /dev/null 2>&1
    then
        echo Server is ready!
        exit 0
    else
        echo Waiting for server ...
        sleep 1
    fi
done

Вместо ssh вам нужно подключиться к серверу через telnet или что-то еще, что вернет успех.

person hendry    schedule 19.05.2010

Чтобы отложить перевод серверного процесса в фоновый режим до тех пор, пока сервер не будет готов обслуживать запросы, у вас может быть сценарий, который запускается на переднем плане, выполняет настройку и/или взаимодействие с пользователем, а затем, когда он готов, он может запускать дочерний сценарий в фоновом режиме с доступом к экспортированным переменным и функциям родителя, а затем выйти. Или он может запустить подоболочку в фоновом режиме с доступом ко всем родительским переменным и функциям.

Вот простой демонстрационный скрипт версии подоболочки:

#!/bin/bash
reps=6                # vars in the parent are available in the subshell
var=123

f() { echo "$@"; }    # a function in the parent is available in the subshell

f "starting"

# this read represents a startup delay for setup, etc., and/or user interaction
read -p "continue now? "

(       # start the subshell
    for ((i=1; i<=reps; i++))
    do
        f "$var" > "/tmp/bg.$$.$i"
        # $$ will be meaningless when the parent script exits
        # because, though it will have the value of the PID of the parent script
        # the parent script will have exited leaving PID=1 (init) as the PPID of the subshell
        # However $BASHPID will be the PID of the backgrounded subshell
        sleep 10    # busy work
    done
) &     # put it in the background

f "process running in background"
f "ending parent"

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

person Dennis Williamson    schedule 20.05.2010

Ниже приведено текущее решение, которое я использую, в котором используется оболочка + Perl. Он использует петлю занятости, но является универсальным (независим от операционной системы).

# any untaken local port will do...
port=1234

#...

httpd_is_ready () {
    "$PERL" -MIO::Socket::INET -e "
local \$| = 1; # turn on autoflush
exit if (IO::Socket::INET->new('127.0.0.1:$port'));
print 'Waiting for \'$httpd\' to start ..';
do {
    print '.';
    sleep(1);
} until (IO::Socket::INET->new('127.0.0.1:$port'));
print qq! (done)\n!;
"
}

#...

start_httpd
url=http://127.0.0.1:$port
httpd_is_ready && "$BROWSER" "$url" || echo $url

IO::Socket::INET находится в ядре Perl с версии 5.006 (perl v5.6.0 ).

person Jakub Narębski    schedule 28.05.2010