Checking if process still running?
Asked Answered
C

9

34

As a way to build a poor-man's watchdog and make sure an application is restarted in case it crashes (until I figure out why), I need to write a PHP CLI script that will be run by cron every 5mn to check whether the process is still running.

Based on this page, I tried the following code, but it always returns True even if I call it with bogus data:

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");

Next, I tried this code...

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

... but don't get what I expect:

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

FWIW, this script is run with the CLI version of PHP 5.2.5, and the OS is uClinux 2.6.19.3.

Thank you for any hint.


Edit: This seems to work fine

exec("ps aux | grep -i 'lighttpd -D' | grep -v grep", $pids);
if(empty($pids)) {
        print "Lighttpd not running!\n";
} else {
        print "Lighttpd OK\n";
}
Conceptualism answered 24/6, 2010 at 15:27 Comment(0)
P
29

I'd use pgrep to do this (caution, untested code):


exec("pgrep lighttpd", $pids);
if(empty($pids)) {

    // lighttpd is not running!
}

I have a bash script that does something similar (but with SSH tunnels):


#!/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


You could alter this script with the commands that you want to monitor.

Pingpingpong answered 24/6, 2010 at 15:44 Comment(3)
Thanks everyone. Calling exec() with grep (pgrep isn't available on the embedded device I'm running this) seems to do the job.Conceptualism
Thought i would share a quick comment here.. Tested pgrep with exec as shown, It appears that the process of exec will quickly create another process...which has the same string in it. So it always returns a single ID.. thinking perhaps using something like if count = 2... So far using a count=2 works.. But just a word of caution here...Membership
I'm using php 7.1 and Amazon Linux and do not have a duplicated process.Insular
E
47

If you're doing it in php, why not use php code:

In the running program:

define('PIDFILE', '/var/run/myfile.pid');

file_put_contents(PIDFILE, posix_getpid());
function removePidFile() {
    unlink(PIDFILE);
}
register_shutdown_function('removePidFile');   

Then, in the watchdog program, all you need to do is:

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);
}

Basically, posix_kill has a special signal 0 that doesn't actually send a signal to the process, but it does check to see if a signal can be sent (the process is actually running).

And yes, I do use this quite often when I need long running (or at least watchable) php processes. Typically I write init scripts to start the PHP program, and then have a cron watchdog to check hourly to see if it's running (and if not restart it)...

Eula answered 24/6, 2010 at 16:9 Comment(4)
Thanks for this awesome answer ircmaxell. What could be the difference between !file_exists($pidFile) and !is_file($pidFile) in this case?Seepage
@RafaSashi: "file_exists — Checks whether a file or directory exists" (link). So the if checks both that it exists and that it is a file.Kacey
What would happen if the script being watched shut down abnormally such that removePidFile() didn't run, and then another process on the system was started that was assigned the same PID? It seems your watchdog script would consider that your script being watched was still running. Maybe there's a way to not only verify that a script with PID X is running, but that it's actually the process that you want to be watching.Graeme
I ran the script under CLI and couldn't get file_put_contents() to create the pid file: failed to open stream: Permission deniedKelantan
P
29

I'd use pgrep to do this (caution, untested code):


exec("pgrep lighttpd", $pids);
if(empty($pids)) {

    // lighttpd is not running!
}

I have a bash script that does something similar (but with SSH tunnels):


#!/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


You could alter this script with the commands that you want to monitor.

Pingpingpong answered 24/6, 2010 at 15:44 Comment(3)
Thanks everyone. Calling exec() with grep (pgrep isn't available on the embedded device I'm running this) seems to do the job.Conceptualism
Thought i would share a quick comment here.. Tested pgrep with exec as shown, It appears that the process of exec will quickly create another process...which has the same string in it. So it always returns a single ID.. thinking perhaps using something like if count = 2... So far using a count=2 works.. But just a word of caution here...Membership
I'm using php 7.1 and Amazon Linux and do not have a duplicated process.Insular
S
14

You can try this, which combines bits of those two approaches:

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

If that doesn't work, you may want to just try running the ps command on your system and seeing what output it gives.

Stray answered 24/6, 2010 at 15:43 Comment(0)
D
8

Try this one

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

Function checks whether process file is exists in /proc/ root directory. Works for Linux only

Darbie answered 28/2, 2013 at 7:59 Comment(1)
To clarify, this will only necessarily work for Linux. There is no guarantee that other UNIX boxes will have a /proc/ directoryKrishna
G
1
<?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";
}

?>
Gilpin answered 27/12, 2012 at 19:43 Comment(0)
Q
1

I didn't see this mentioned here, but here's another approach taking the second grep out of the equation, i use this with alot of my PHP scripts and should work universally

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

Enjoy.

Quinquennium answered 21/8, 2013 at 4:10 Comment(1)
This is always going to have $pids as the whole command is one?Germanous
D
1

The main problem is the if you run a php script, the exec command will be run as the web-servers user (www-data); this user can't see pid's from other users, unless you use "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");
?>

More information about the script here http://umbru.ch/?p=328

Demars answered 18/4, 2015 at 11:27 Comment(0)
B
0

i have a function to get the pid of a process...

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;
}
Burnard answered 24/6, 2010 at 15:48 Comment(0)
R
-1

To check whether process is running by its name, you can use pgrep, e.g.

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

or:

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

as per this post.

If you know the PID of the process, you can use one the following functions:

  /**
   * 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"));
  }

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

Rembert answered 4/7, 2017 at 12:17 Comment(1)
$return returns 0 regardless if the process is running. Rather, you should be looking at $output which returns an array containing process id's. it's important to note that exec() will generate its own process, and include itself in that array, meaning it will always return at least 1 process id. so a count() greater than 2, means the process you are looking for, is actually running.Graphitize

© 2022 - 2024 — McMap. All rights reserved.