【问题标题】:Checking if process still running?检查进程是否仍在运行?
【发布时间】:2011-03-07 21:16:18
【问题描述】:

作为一种构建穷人看门狗并确保应用程序在崩溃时重新启动(直到我弄清楚原因)的一种方法,我需要编写一个 PHP CLI 脚本,该脚本将由 cron 每 500 万次运行一次以检查进程是否仍在运行。

基于this page,我尝试了以下代码,但即使我用虚假数据调用它也总是返回True:

function processExists($file = false) {
    $exists= false;
    $file= $file ? $file : __FILE__;

    // Check if file is in process list
    exec("ps -C $file -o pid=", $pids);
    if (count($pids) > 1) {
    $exists = true;
    }
    return $exists;
}

#if(processExists("lighttpd"))
if(processExists("dummy"))
    print("Exists\n")
else
    print("Doesn't exist\n");

接下来,我尝试了this code...

(exec("ps -A | grep -i 'lighttpd -D' | grep -v grep", $output);)
print $output;

...但没有得到我的期望:

/tmp> ./mycron.phpcli 
Arrayroot:/tmp> 

FWIW,此脚本使用 PHP 5.2.5 的 CLI 版本运行,操作系统为 uClinux 2.6.19.3。

感谢您的任何提示。


编辑:这似乎工作正常

exec("ps aux | grep -i 'lighttpd -D' | grep -v grep", $pids);
if(empty($pids)) {
        print "Lighttpd not running!\n";
} else {
        print "Lighttpd OK\n";
}

【问题讨论】:

    标签: php linux process exec


    【解决方案1】:

    试试这个

    function processExists ($pid) {
        return file_exists("/proc/{$pid}");
    }
    

    函数检查/proc/根目录中是否存在进程文件。 仅适用于 Linux

    【讨论】:

    • 澄清一下,这只适用于 Linux。不能保证其他 UNIX 机器会有 /proc/ 目录
    【解决方案2】:

    要检查进程是否按名称运行,可以使用pgrep,例如

    $is_running = shell_exec("pgrep -f lighttpd");
    

    或:

    exec("pgrep lighttpd", $output, $return);
    if ($return == 0) {
        echo "Ok, process is running\n";
    }
    

    根据这个post

    如果你知道进程的PID,你可以使用以下函数之一:

      /**
       * Checks whether the process is running.
       *
       * @param int $pid Process PID.
       * @return bool
       */
      public static function isProcessRunning($pid) {
        // Calling with 0 kill signal will return true if process is running.
        return posix_kill((int) $pid, 0);
      }
    
      /**
       * Get the command of the process.
       * For example apache2 in case that's the Apache process.
       *
       * @param int $pid Process PID.
       * @return string
       */
      public static function getProcessCommand($pid) {
        $pid = (int) $pid;
        return trim(shell_exec("ps o comm= $pid"));
      }
    

    相关:How to check whether specified PID is currently running without invoking ps from PHP?

    【讨论】:

    • $return 返回0,无论进程是否正在运行。相反,您应该查看$output,它返回一个包含进程ID 的数组。重要的是要注意exec() 将生成自己的进程,并将自己包含在该数组中,这意味着它将始终返回至少 1 个进程 ID。所以 count() 大于 2,表示您正在寻找的进程实际上正在运行。
    【解决方案3】:

    主要问题是如果你运行一个 php 脚本,exec 命令将以 web-servers 用户(www-data)运行;此用户无法看到其他用户的 pid,除非您使用“pidof”

    <?php
    //##########################################
    // desc: Diese PHP Script zeig euch ob ein Prozess läuft oder nicht
    // autor: seevenup
    // version: 1.3
    // info: Da das exec kommando als apache user (www-data) ausgefuert
    //       wird, muss pidof benutzt werden da es prozesse von
    //       anderen usern anzeigen kann
    //##########################################
    
    if (!function_exists('server_status')) {
            function server_status($string,$name) {
                    $pid=exec("pidof $name");
                    exec("ps -p $pid", $output);
    
                    if (count($output) > 1) {
                            echo "$string: <font color='green'><b>RUNNING</b></font><br>";
                    }
                    else {
                            echo "$string: <font color='red'><b>DOWN</b></font><br>";
                    }
            }
    }
    
    //Beispiel "Text zum anzeigen", "Prozess Name auf dem Server"
    server_status("Running With Rifles","rwr_server");
    server_status("Starbound","starbound_server");
    server_status("Minecraft","minecarf");
    ?>
    

    这里有更多关于脚本的信息http://umbru.ch/?p=328

    【讨论】:

      【解决方案4】:

      我没有看到这里提到这一点,但这是另一种方法,将第二个 grep 排除在等式之外,我将它与我的很多 PHP 脚本一起使用,并且应该可以通用

      exec("ps aux | grep -i '[l]ighttpd -D'", $pids);
      if(empty($pids)) {
              print "Lighttpd not running!\n";
      } else {
              print "Lighttpd OK\n";
      }
      

      享受吧。

      【讨论】:

      • 这总是有$pids,因为整个命令都是一个?
      【解决方案5】:
      <?php
      
      function check_if_process_is_running($process)
      {
          exec("/bin/pidof $process",$response);
          if ($response)
          {
               return true;
          } else
          {
               return false;
          }
      }
      
      if (check_if_process_is_running("mysqld"))
      {
            echo "MySQL is running";
      } else
      {
            echo "Mysql stopped";
      }
      
      ?>
      

      【讨论】:

        【解决方案6】:

        我会使用@987654321@ 来执行此操作(注意,未经测试的代码):

        exec("pgrep lighttpd", $pids); if(empty($pids)) { // lighttpd is not running! }

        我有一个执行类似操作的 bash 脚本(但使用 SSH 隧道):

        #!/bin/sh MYSQL_TUNNEL="ssh -f -N -L 33060:127.0.0.1:3306 tunnel@db" RSYNC_TUNNEL="ssh -f -N -L 8730:127.0.0.1:873 tunnel@db" # MYSQL if [ -z `pgrep -f -x "$MYSQL_TUNNEL"` ] then echo Creating tunnel for MySQL. $MYSQL_TUNNEL fi # RSYNC if [ -z `pgrep -f -x "$RSYNC_TUNNEL"` ] then echo Creating tunnel for rsync. $RSYNC_TUNNEL fi

        您可以使用要监视的命令来更改此脚本。

        【讨论】:

        • 谢谢大家。用 grep 调用 exec() (我正在运行的嵌入式设备上没有 pgrep)似乎可以完成这项工作。
        • 我想在这里分享一个简短的评论.. 测试pgrepexec 如图所示,似乎 exec 的进程将快速创建另一个进程...其中具有相同的字符串它。所以它总是返回一个 ID.. 考虑可能使用类似 if count = 2 的东西......到目前为止,使用 count=2 是可行的.. 但这里只是一个警告......
        • 我使用的是 php 7.1 和 Amazon Linux,并且没有重复的进程。
        【解决方案7】:

        如果你是用 php 做的,为什么不使用 php 代码:

        在正在运行的程序中:

        define('PIDFILE', '/var/run/myfile.pid');
        
        file_put_contents(PIDFILE, posix_getpid());
        function removePidFile() {
            unlink(PIDFILE);
        }
        register_shutdown_function('removePidFile');   
        

        那么,在看门狗程序中,你需要做的就是:

        function isProcessRunning($pidFile = '/var/run/myfile.pid') {
            if (!file_exists($pidFile) || !is_file($pidFile)) return false;
            $pid = file_get_contents($pidFile);
            return posix_kill($pid, 0);
        }
        

        基本上,posix_kill 有一个特殊的信号 0,它实际上不会向进程发送信号,但它会检查是否可以发送信号(进程实际上正在运行)。

        是的,当我需要长时间运行(或至少是可观察的)php 进程时,我确实经常使用它。通常我编写初始化脚本来启动 PHP 程序,然后有一个 cron 看门狗每小时检查一次以查看它是否正在运行(如果没有重新启动它)......

        【讨论】:

        • 感谢 ircmaxell 的精彩回答。在这种情况下 !file_exists($pidFile) 和 !is_file($pidFile) 有什么区别?
        • @RafaSashi: "file_exists — 检查文件或目录是否存在" (link)。所以 if 会检查它是否存在以及它是一个文件。
        • 如果被监视的脚本异常关闭导致removePidFile() 没有运行,然后系统上另一个分配了相同PID 的进程启动,会发生什么情况?看来您的看门狗脚本会认为您正在监视的脚本仍在运行。也许有一种方法不仅可以验证具有 PID X 的脚本是否正在运行,而且它实际上是您想要监视的进程。
        • 我在 CLI 下运行脚本,无法获取 file_put_contents() 来创建 pid 文件:failed to open stream: Permission denied
        【解决方案8】:

        你可以试试这个,它结合了这两种方法:

        function processExists($processName) {
            $exists= false;
            exec("ps -A | grep -i $processName | grep -v grep", $pids);
            if (count($pids) > 0) {
                $exists = true;
            }
            return $exists;
        }
        

        如果这不起作用,您可能只想尝试在系统上运行 ps 命令并查看它给出的输出。

        【讨论】:

          【解决方案9】:

          我有一个函数来获取进程的 pid...

          function getRunningPid($processName) {
              $pid = 0;
              $processes = array();
              $command = 'ps ax | grep '.$processName;
              exec($command, $processes);
              foreach ($processes as $processString) {
                  $processArr = explode(' ', trim($processString));
                      if (
                      (intval($processArr[0]) != getmypid())&&
                      (strpos($processString, 'grep '.$processName) === false)
                  ) {
                      $pid = intval($processArr[0]);
                  }
              }
              return $pid;
          }
          

          【讨论】:

            最近更新 更多