ehiller
ehiller

Reputation: 1547

Insane crond behavior. keeps making defunct bash processes

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: Init.d script hanging

Upvotes: 1

Views: 6653

Answers (4)

Beano
Beano

Reputation: 7851

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

Upvotes: 10

Dennis Williamson
Dennis Williamson

Reputation: 360325

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

Upvotes: 2

Mike Axiak
Mike Axiak

Reputation: 12004

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.

Upvotes: 2

grossvogel
grossvogel

Reputation: 6782

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.

Upvotes: 0

Related Questions