views:

106

answers:

4

I have a crontab that looks like:

SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root
HOME=/

0-59 * * * * /var/www/html/private/fivemin/zdaemon.php >> /dev/null &

Simple as possible, right?

zdaemon.php which I am just testing with is:

#!/usr/bin/php
<?


while(true){
        sleep(1);
}

?>

Whenever it runs it hangs like:

root     15532  0.0  0.1 57228 1076 ?        Ss   19:09   0:00 crond
root     16681  0.0  0.1 72196 1428 ?        S    21:46   0:00 crond
root     16682  0.0  0.0     0    0 ?        Zs   21:46   0:00 [bash] <defunct>
root     16683  0.0  0.5 54800 5740 ?        S    21:46   0:00 /usr/bin/php /var/www/html/private/fivemin/zdaemon.php
root     16687  0.0  0.1 72196 1428 ?        S    21:47   0:00 crond
root     16688  0.0  0.0     0    0 ?        Zs   21:47   0:00 [bash] <defunct>
root     16689  0.0  0.5 54800 5740 ?        S    21:47   0:00 /usr/bin/php /var/www/html/private/fivemin/zdaemon.php

I have been banging my brain against a wall on this all day. Has anyone seen this before? Any ideas at all?

This is a reference to: http://stackoverflow.com/questions/3589786/init-d-script-hanging

+1  A: 

I think your main problem is that the stderr is still going to the shell but the child process (your php process) is sleeping, resulting in the zombie process. Try this:

0-59 * * * * /var/www/html/private/fivemin/zdaemon.php &> /dev/null &

If you're still having problems with a zombie process, take a look at nohup.

Mike Axiak
Just noticed this is the correct answer as well!
variable
A: 

The usual way to create a daemon is to fork a child process to do the work, then exit the parent process with an error code of 0. I don't know for sure that this is your problem, though.

I haven't done this in php, but you could use pcntl_fork() to mimic the usual c way.

grossvogel
it should be noted that starting a daemon with fork() is not trivial, and you usually have to fork twice to do it right.
Mike Axiak
A: 

It seems odd to me to background a process in a crontab. Try removing the & at the end of the line.

Dennis Williamson
+1  A: 

A zombie process is not necessarily a bad thing in itself. It indicates that the child process has died, and the parent process has not yet reaped its status (using wait() or a related system call).

What is happening is as follows - cron is interested in stderr from the script it starts (so that it can email it to you should the script fail), therefore it creates a pipe which is attaches stderr of the script to write end (file descriptor 2). Then cron sits reading on the read end of the pipe, waiting for the script to exit and read eof (read() of zero bytes) - it then reaps the return status of the script.

In your example, the daemon spawned, inherits the stderr file descriptor, and therefore when the intermediate shell exits (and becomes defunct), the pipe is held open by the daemon. Therefore cron never reads eof and hence never reaps the return status.

The solution is to ensure that stderr of your daemon is closed. This can be achieved as follows:

0-59 * * * * /var/www/html/private/fivemin/zdaemon.php >> /dev/null 2>&1 &

which will write both stdout and stderr to /dev/null

Beano
variable