我目前正在构建一个应该启动外部进程的Laravel应用程序,然后使用进程ID监视其状态。
进程就像这样开始,返回pid:
exec('nohup <script> & echo $!');
这很好用。但是现在我在跟踪新启动的进程的状态时遇到了问题,可能是因为我使用的方法要求已检查的进程是执行命令的shell的子进程。
目前我尝试通过以下方式确定流程是否仍在运行:
exec("ps -p $pid -o pid=") == $pid;
如果进程仍在运行,则会重新运行true
,但仅适用于子进程。我应该可以在这里使用kill -0 <pid>
,所以这不是一个大问题。
问题是什么问题是确定流程的退出代码。我目前的代码如下:
exec("wait $pid; echo \$?");
当流程结束时,wait
应立即返回并将退出代码写入$?
。但是这个也只适用于执行原始命令的shell的子进程,所以我总是得到退出代码127
(不是这个shell的子代)。
有没有其他方法可以获取流程的退出代码?
此外,我使用相同的Laravel队列来启动和监视进程(使用php artisan queue:listen
命令),以便在同一进程中调用exec()
方法 。或者PHP是否为每个exec()
调用启动了一个单独的shell?
编辑:我现在知道Laravel确实为每个排队的命令启动了一个新进程,因此启动脚本并监视其状态是在不同的进程中完成的。
答案 0 :(得分:3)
I've now worked around this issue by writing the exit code to a log file once the long running script is finished. By adding this to the initial command, I can "fire and forget" the process and check the status code from the log file later.
This is the command (wasn't really easy to come by):
$pid = exec('('.
// don't listen to the hangup signal
// invoke the script and write the output to the log file
"nohup $script >> $logFile 2>&1; ".
// when the script is finished, write the exit code to the log file
'echo "Exit code $?" >> '.$logFile.
// discard the output of the `()' part so exec() doesn't
// wait for the process to be finished,
// then send the `()' part to the background
') > /dev/null 2>&1 & '.
// immediately return the process id of the background process
'echo $!');
Monitoring the running process works well using the kill -0
method with the process ID:
// true if the process is still running
exec("kill -s 0 $pid 1>/dev/null 2>&1; echo $?") === '0'
This requires the PHP/Apache user to be able to send a kill signal to the process but this requirement should be met because the process was launched by the same user that now tries to monitor it.
Once the process is no longer running, I can determine if it was successful by checking the log file.
答案 1 :(得分:2)
exec()
函数实际上接受了用于捕获进程的进程输出和退出代码的其他参数。
示例:
exec('nohup <script>', $output, $code);
var_dump($code);
应输出:int(0)
或预期的任何状态代码。