疯狂的crond行为。不断制作失效的 bash 进程
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3748432/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Insane crond behavior. keeps making defunct bash processes
提问by ehiller
I have a crontab that looks like:
我有一个看起来像的 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 &
Simple as possible, right?
尽量简单吧?
zdaemon.php which I am just testing with is:
我刚刚测试的 zdaemon.php 是:
#!/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
这是参考:Init.d script hang
回答by Beano
A zombieprocess is not necessarily a bad thing in itself. It indicates that the childprocess has died, and the parentprocess has not yet reaped its status (using wait()or a related system call).
一个僵尸进程不一定本身是一件坏事。它表明子进程已经死亡,父进程还没有获得它的状态(使用wait()或相关的系统调用)。
What is happening is as follows - cronis interested in stderrfrom the script it starts (so that it can email it to you should the script fail), therefore it creates a pipewhich is attaches stderrof the script to write end (file descriptor 2). Then cronsits 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.
发生的事情如下 -对它启动的脚本cron中的stderr感兴趣(以便在脚本失败时它可以通过电子邮件将其发送给您),因此它创建了一个管道,该管道将脚本的stderr附加到写入结束(文件描述符 2 )。然后cron在管道的读取端读取,等待脚本退出并读取eof(read()零字节) - 然后获取脚本的返回状态。
In your example, the daemon spawned, inherits the stderrfile descriptor, and therefore when the intermediate shell exits (and becomes defunct), the pipe is held open by the daemon. Therefore cronnever reads eofand hence never reaps the return status.
在您的示例中,守护进程产生并继承了stderr文件描述符,因此当中间 shell 退出(并失效)时,管道由守护进程保持打开状态。因此cron永远不会读取eof,因此永远不会获得返回状态。
The solution is to ensure that stderrof your daemon is closed. This can be achieved as follows:
解决方案是确保您的守护进程的stderr已关闭。这可以通过以下方式实现:
0-59 * * * * /var/www/html/private/fivemin/zdaemon.php >> /dev/null 2>&1 &
which will write bothstdoutand stderrto /dev/null
这将写两个标准输出和标准错误,以/dev/null
回答by Mike Axiak
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:
我认为您的主要问题是 stderr 仍在进入 shell,但子进程(您的 php 进程)正在休眠,从而导致僵尸进程。尝试这个:
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.
如果您仍然遇到僵尸进程的问题,请查看nohup。
回答by Paused until further notice.
It seems odd to me to background a process in a crontab. Try removing the &at the end of the line.
在 crontab 中为进程做后台处理对我来说似乎很奇怪。尝试删除&行尾的 。
回答by grossvogel
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.
创建守护进程的常用方法是派生一个子进程来完成这项工作,然后以错误代码 0 退出父进程。不过,我不确定这是你的问题。
I haven't done this in php, but you could use pcntl_fork()to mimic the usual c way.
我没有在 php 中做过这个,但是你可以使用pcntl_fork()来模仿通常的 c 方式。

