疯狂的crond行为。继续制作已失效的bash流程

时间:2010-09-20 02:54:08

标签: php bash centos cron crontab

我有一个crontab,看起来像:

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

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

尽可能简单,对吧?

我正在测试的zdaemon.php是:

#!/usr/bin/php
<?


while(true){
        sleep(1);
}

?>

无论何时运行,它都会挂起:

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

这一整天,我一直在撞墙。谁看过这个吗?有什么想法吗?

这是对Init.d script hanging

的引用

4 个答案:

答案 0 :(得分:8)

zombie 进程本身并不一定是坏事。它表示进程已经死亡,进程尚未获得其状态(使用wait()或相关的系统调用)。

正在发生的事情如下 - cron对它启动的脚本中的 stderr 感兴趣(如果脚本失败,它可以通过电子邮件发送给您),因此它会创建一个 pipe ,它附加脚本的 stderr 以写入结尾(文件描述符2)。然后cron坐在读取管道的读取端,等待脚本退出并读取 eof (零{/ 1}}零字节) - 然后它收获返回状态脚本。

在您的示例中,生成的守护程序继承了 stderr 文件描述符,因此当中间shell退出(并且变得不存在)时,管道将由守护程序保持打开状态。因此,read()永远不会读取 eof ,因此永远不会获得返回状态。

解决方案是确保您的守护程序的 stderr 已关闭。这可以通过以下方式实现:

cron

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

答案 1 :(得分:2)

我认为你的主要问题是stderr仍然是shell,但子进程(你的php进程)正在休眠,导致僵尸进程。试试这个:

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

如果您仍然遇到僵尸进程问题,请查看nohup

答案 2 :(得分:2)

在crontab中对一个进程进行后台处理似乎很奇怪。尝试删除该行末尾的&

答案 3 :(得分:0)

创建守护进程的常用方法是派生子进程执行工作,然后退出父进程,错误代码为0.我不确定这是否是您的问题。

我没有在php中完成此操作,但您可以使用pcntl_fork()来模仿the usual c way