How to delay putting process in background until after it is ready to serve, in shell
I have two p开发者_JS百科rocesses: a server that should be run in background, but starts serving requests after a delay, and a client that should be started when server is ready. The server prints line containg "Acceptin connections" to its stderr when ready (server stderr is redirected to a file when running it in background).
How to delay putting server process in background until server is ready to serve requests? Alternatively, how to delay running client until server is ready?
Language: shell script (or optionally Perl).
Added 2010-05-19 22:34 +0000:
It is known upfront which TCP port the server would listen to for requests.
Note: server is web server (plackup running HTTP::Server::PSGI), client is web browser, e.g. lynx.
You can have a while loop that keeps checking the server's log file for that line. grep
will return 1 if no matches are found:
false
while [ $? != 0 ]; do
grep 'Accepting connections' server.log
done
run-client
Use a while loop:
while : do if ssh root@127.0.0.1 -p 1202 echo > /dev/null 2>&1 then echo Server is ready! exit 0 else echo Waiting for server ... sleep 1 fi done
Instead of ssh you need to telnet or something to your server that returns success.
In order to elay putting server process in background until server is ready to serve requests, you can have a script that starts in the foreground, performs setup and/or user interaction then when it's ready it can launch a child script in the background with access to the parent's exported variables and functions and then exit. Or it can launch a subshell in the background with access to all the parents variables and functions.
Here's a simple demo script of the subshell version:
#!/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"
By the way, if the subshell had not been sent to the background, its changes to its environment would not be available to its parent (which is also true in the demo above, in any case).
Below there is current solution that I use, which uses shell + Perl. It uses busy loop, but is universal (should be independent on operating system).
# 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 is in Perl core since 5.006 (perl v5.6.0).
精彩评论