【问题标题】:Start and monitor process with exec()使用 exec() 启动和监控进程
【发布时间】:2015-06-13 12:29:38
【问题描述】:

我目前正在构建一个 Laravel 应用程序,它应该启动外部进程,然后使用进程 ID 监控它们的状态。

进程是这样​​启动的,返回 pid:

exec('nohup <script> & echo $!');

这很好用。但是现在我在跟踪新启动进程的状态时遇到了问题,大概是因为我使用的方法要求被检查的进程是执行命令的 shell 的子进程。

目前我尝试通过以下方式确定进程是否仍在运行:

exec("ps -p $pid -o pid=") == $pid;

如果进程仍在运行但仅适用于子进程,则返回true。我应该可以在这里改用kill -0 &lt;pid&gt;,所以这不是什么大问题。

是什么,不过,问题在于确定进程的退出代码。我当前的代码如下所示:

exec("wait $pid; echo \$?");

当进程完成时,wait 应该立即返回并将退出代码写入$?。但是这个只适用于执行原始命令的shell的子进程,所以我总是得到退出代码127(不是这个shell的子进程)。

还有其他方法可以获取进程的退出码吗?

另外,我使用相同的 Laravel 队列来启动和监视进程(使用 php artisan queue:listen 命令),所以 exec() 方法 在同一个进程中被调用。还是 PHP 会为每个 exec() 调用启动一个单独的 shell?

编辑:我现在知道 Laravel 确实为每个排队的命令启动一个新进程,因此启动脚本和监控它们的状态是在不同的进程中完成的。

【问题讨论】:

    标签: php shell laravel


    【解决方案1】:

    我现在通过在长时间运行的脚本完成后将退出代码写入日志文件来解决此问题。通过将它添加到初始命令中,我可以“触发并忘记”该过程并稍后从日志文件中检查状态代码。

    这是命令(来之不易):

    $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 用户能够向进程发送终止信号,但应该满足此要求,因为该进程是由现在尝试监视它的同一用户启动的。

    一旦进程不再运行,我可以通过检查日志文件来确定它是否成功。

    【讨论】:

      【解决方案2】:

      exec() 函数实际上接受额外的参数来捕获进程输出和进程的退出代码。

      示例:

      exec('nohup <script>', $output, $code); var_dump($code);

      应该输出:int(0) 或任何预期的状态码。

      更多信息请参见http://us2.php.net/manual/en/function.exec.php

      【讨论】:

      • 这也适用于后台进程吗? nohup &lt;script&gt; &amp; 在后台启动,PHP 脚本不会等待进程完成(因为它可能是一个长时间运行的进程)。
      • 很遗憾没有。您可以尝试使用pcntl_fork() 分叉 PHP 进程,然后在进程分叉时运行我上面所说的。这是一个很好的例子:php.net/manual/en/function.pcntl-fork.php#110790
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-09-22
      • 1970-01-01
      • 2011-04-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多