我目前正在构建一个 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 确实为每个排队命令启动一个新进程,因此启动脚本并监视其状态是在不同的进程中完成的。
最佳答案
我现在已经解决了这个问题,方法是在长时间运行的脚本完成后将退出代码写入日志文件。通过将其添加到初始命令中,我可以“触发并忘记”该进程,并稍后从日志文件中检查状态代码。
这是命令(并不容易获得):
$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 $!');
使用带有进程 ID 的 kill -0
方法可以很好地监视正在运行的进程:
// true if the process is still running
exec("kill -s 0 $pid 1>/dev/null 2>&1; echo $?") === '0'
这要求 PHP/Apache 用户能够向进程发送终止信号,但应该满足此要求,因为该进程是由现在尝试监视它的同一用户启动的。
一旦进程不再运行,我可以通过检查日志文件来确定它是否成功。
关于php - 使用 exec() 启动和监视进程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30818686/