3

I am running a rewrite map with an external rewrite program (prg) in apache2 that may produce an error and die. When the rewrite map is not running any more the system obviously doesn't function properly.

So I wanted to start a simple wrapper shell script that itself executes map program (which is written in php) and restarts it if it dies:

#!/bin/bash
until /usr/bin/php /somepath/mymap.php; do
  echo "map died but i will restart it right away!" 
done

If I try that in the shell by hand, it works fine, however it does not work when started by the webserver.

...and then communicates with the rewriting engine via its stdin and stdout file-handles. For each map-function lookup it will receive the key to lookup as a newline-terminated string on stdin. It then has to give back the looked-up value as a newline-terminated string on stdout or the four-character string ``NULL'' if it fails...

The reason seems pretty clear to me. The first script takes stdin but doesn't redirect it to the sub script.

I guess I somehow need to define a descriptor using exec and redirect stdin/stdout of the scripts properly. But how do I do that?

The Surrican
  • 29,118
  • 24
  • 122
  • 168
  • 1
    A new mymap.php will automatically have stdin and stdout properly assigned. "The reason seems pretty clear to me" - well, not to me. – kubanczyk Jan 03 '12 at 17:53
  • thats why i am posting this question here ;) i think it often happens that people can't solve a problem because trivial thoughts get caught up in some misdirection – The Surrican Jan 04 '12 at 10:52

3 Answers3

3

It's a common problem that some script works executed "by hand" and do not work when executed indirectly (via cron or from apache).

Usually the root cause is one of:

  1. your script needs some extra environment varaible (PATH, LD_LIBRARY_PATH, etc.)
  2. your script requires terminal

First thing to do is to grab some debug info, so add to your script:

env > /tmp/$0.env # get environment

and get stderr:

... /usr/bin/php /somepath/mymap.php 2>/tmp/$0.stderr ...

This may lead you to the solution.

If your script requires terminal and you cannot fix it you can run your script via gnu screen.

Good luck.

Michał Šrajer
  • 30,364
  • 7
  • 62
  • 85
2

Michał Šrajer has given one very common cause of trouble (environment). You should certainly be sure that the environment is sufficiently well set up, because Apache sets its own environment rigorously and does not pass on any inherited junk values; it only passes what it is configured to pass (SetEnv and PassEnv directives, IIRC).

Another problem is that you think your mapping process will fail; that's worrying. Further, it is symptomatic of yet another problem, which I think is the main one.

The first time the map process is run, it will read the request from the web server, but if the mapping fails, you rerun it - but the web server is still waiting for the output from the original request, and the map process is waiting for the input, so there's an impasse.

Note that a child process automatically inherits the standard input and standard output of its parent unless you do something to change it.

If you think things might fail, you'll need to capture the standard input so that when you rerun the program, you can resupply the input (though why it would work on the second time when it failed on the first is a separate mystery).

Maybe:

if tee /tmp/xx.$$ | /usr/bin/php /somepath/mymap.php
then : OK
else
     until /usr/bin/php /somepath/mymap.php < /tmp/xx.$$
     do echo "map died but I will restart it right away!"
     done
fi
rm -f /tmp/xx.$$

Unresolved issues include:

  • You should add traps to ensure that the temporary file is removed;
  • You should probably not use /tmp as the directory;
  • The messages probably do not get sent to the web server and from thence to the client browser until the overall script terminates, so the echoed messages simply mess up the start of the response;
  • There is no limit on the number of failures;
  • There is no logging of the failures;
  • There is no attempt to fix the problem that caused the failure;
  • And there are probably others I've not thought of yet.
Community
  • 1
  • 1
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • great idea to "buffer" the input for the failed attempt and to think of that impasse. the requests are not critical, and those who might cause the map to crash, are probably not valid ones anyway. i don't need to make sure every request gets processed properly, i just need to ensure that the map doesn't stop. as it seems the problem lies not in the direction i thought, it think i will do something in the directino you proposed anway and thanks for the great remarks. – The Surrican Jan 04 '12 at 10:50
1

until is not a valid keyword, you probably have it aliased and aliases do not work on scripts. my mistake, it seems it is.

regardless, this is what you want to do:

while true; do
    /usr/bin/php /somepath/mymap.php
done

if this also fails then yes, either your program expects a terminal or you have something missing in your env.

Samus_
  • 2,903
  • 1
  • 23
  • 22