I would like to have a shell scipt that runs infinitely and keeps checking status of a php script (say my.php) and restarts it if the script has terminated somehow. I have the idea to go for -
ps -aux | grep "my.php"
and then use the result of this to check the status and do accordingly. Thanks in advance.
You can simply say:
ps -aux | grep -q "my.php" || php -f my.php
The way it works is that grep -q will not output anything but will return an "OK" exit code if it found something. when it returns a "NOT OK" exit code, the part after the || ("or") gets executed (because of boolean short-circuit evaluation - look it up).
You also need to make sure that:
you run the new script in the background and detach it from your console so that your script can keep monitoring
when you run ps | grep sometimes ps also lists your grep and then the grep "greps itself", so you have to filter that out.
It should look something like this:
while true
ps -aux | grep -v grep | grep -q "my.php" || ( nohup php -f "my.php" & )
sleep 1
done
or some-such..
Another approach is, start your php-program in a loop:
for ((;;))
do
my.php
done
With Linux ps, you could use
ps -C "my.php"
instead of grep, to identify my.php. Grep commands often find themselves. Maybe your ps has a similar switch?
If you DO really feel the need to grep the output of ps, beware of your grep finding itself.
[ghoti#pc ~]$ sleep 60 &
[1] 66677
[ghoti#pc ~]$ ps aux | grep sleep
ghoti 66677 0.0 0.0 3928 784 11 S 4:11PM 0:00.00 sleep 60
ghoti 66681 0.0 0.0 16440 1348 11 S+ 4:12PM 0:00.00 grep sleep
[ghoti#pc ~]$
There's an easy way to avoid this. Just make part of your grep into a more complex regular expression.
[ghoti#pc ~]$ sleep 60 &
[2] 66717
[ghoti#pc ~]$ ps aux | grep '[s]leep'
ghoti 66677 0.0 0.0 3928 784 11 S 4:11PM 0:00.00 sleep 60
ghoti 66717 0.0 0.0 3928 784 11 S 4:13PM 0:00.00 sleep 60
[ghoti#pc ~]$
On the other hand, if you just want to make sure that your PHP script always runs, you can wrap it in something that re-runs it when it dies:
while true; do
php /path/to/my.php
done
If you want this to run at startup, you can edit your crontab on the server, and use a #reboot tag, assuming you're using "Vixie" cron (common on Linux and BSD):
#reboot /path/to/wrapperscript
You can man crontab and man 5 crontab for more details on how to use cron and the #reboot tag.
Related
What i want to achieve
I want to execute some script it it's process in not started on the server. so for that i am preparing the command in shell script and executing it in single line.
Command with php variable
$cmd = "if [[ `ps auxww | grep -v grep | grep ".$process_file." | grep '".$find."'` == '' ]] ; then ".$cmd2." fi";
echo $cmd."\n";
Executed command, once variables are replaced (what will actually run on bash):
if [[ `ps auxww | grep -v grep | grep /home/new_jig.php | grep 'test_51 1714052'` == '' ]] ; then php /home/new_jig.php test_51 1714052 & fi;
executing command
exec($cmd,$out,$res);
Please note that, I have also split the problem in to two statement and execute those. But it is time consuming. It is causing problems when I have more than 2000 in list, and the command is executed for all. This takes about 1 or more than 1 minute to reach to the last number.
I want to achieve this within 10 seconds. Please help me to reach optimum output.
Thanks
Jignesh
somehow I am able to make it execute with the following command
$process_file = phpfile which executing some functionality
$cmd2 = " php ".$process_file." 1212 >/dev/null 2>/dev/null & ";
$cmd11 ="if ps -auxw | grep -v grep | grep '".$process_file."' | grep '".$find."' &> /dev/null ; then echo 1;".$cmd2."; fi";
shell_exec($cmd11." >/dev/null 2>/dev/null &");
Before this: for 1100 request the process was taking about 60+ seconds
After this: it is getting completed between 20 to 30 seconds
I am developing some PHP scripts on a Namecheap shared server. I accidentally made a loop which seems to go on indefinitely (or for a very long time), so now I am trying to kill it using SSH.
I have viewed a list of running processes with top, found the misbehaving PHP script, and tried to kill it with kill. However, after I kill it with this command, when I try using the ps, it is still running!
The result of the ps:
PID TTY STAT TIME COMMAND
819520 ? S 0:00 /usr/bin/php /my/php/file.php
I have tried killing the process over and over, but it just won't die!
The SSH is limited, so I can't use commands like killall. What do I do??!
To kill the process you can do the following:
Get the PID with ps -ef
kill it with kill -9 <pid>
A nice reference: When should I use kill -9?
Just for fun, an example:
$ sleep 100 &
[1] 4156
$ ps -ef | grep slee[p]
me 4156 3501 0 10:34 pts/5 00:00:00 sleep 100
$ kill 4156
[1]+ Terminated sleep 100
$ ps -ef | grep slee[p]
$
You can use 'ps' (process status) to get the ID and then use 'kill' to stop it.
http://linux.about.com/library/cmd/blcmdl_kill.htm
try this command. this will stop file from executing.
pkill -f /my/php/file.php
I want to run only one proccess at a time. So I need to check. I found there was suggestions to use exec()
so I made test functions - one which sleeps 1 minute and one which tests if process is running.
public function test($a='', $b='') {
exec("ps ax | grep 'php -q /var/www/glab/index.php ajax/test2'", $pids);
if (count($pids) > 2) {
$exists = true;
echo 'exists' . count($pids);
print_r($pids);
}
}
And I get result:
exists3Array
(
[0] => 30680 pts/8 S+ 0:00 php -q /var/www/glab/index.php ajax/test2
[1] => 30684 ? S 0:00 sh -c ps ax | grep 'php -q /var/www/glab/index.php ajax/test2'
[2] => 30686 ? S 0:00 grep php -q /var/www/glab/index.php ajax/test2
)
I did not expect 3 processes but I see its ok. Can I be sure that my function is working ok - detecting running when there is > 2, am I not missing something? For example maybe if some user will run some program on linux maybe this will not work anymore?
Or can you sugesst some check which matches only the one process, without sh and grep? I mean exact string. I was trying but cannot make it work to match only one which I am searching.
Edit:
googled bit more and found more examples, adjusted and have this:
exec ('ps -efa | grep "php -q /var/www/glab/index.php ajax/test2" |grep -v "grep " | awk "{print $10 $NF}"', $pids);
print_r($pids);
When process runs:
Array
(
[0] => darius 2046 12877 5 09:23 pts/8 00:00:00 php -q /var/www/glab/index.php ajax/test2
)
It matches now 1 processs. Could you check if this is ok, am I not missing something?
From PHP pages of my apache server, I run some commands using a line like :
exec("{$command} >> /tmp/test.log 2>&1 & echo -n \$!");
You can see an explaination of the arguments here.
But I don't understand something : if I restart or stop my apache server, my command dies too.
root#web2:/sx/temp# ps ax | grep 0ff | grep -v grep
15957 ? S 0:38 /usr/bin/php /sx/site_web_php/fr_FR/app/console task:exec /sx/temp/task_inventaire/ 0ff79bf690dcfdf788fff26c259882e2d07426df 10800
root#web2:/sx/temp# /etc/init.d/apache2 restart
Restarting web server: apache2 ... waiting ..
root#web2:/sx/temp# ps ax | grep 0ff | grep -v grep
root#web2:/sx/temp#
After some researches, I read some things about parent pids, but using a & inside my command-line, I thought I was really detaching my child process from his parent.
I am using apache2 with libapache2-mod-php5 and apache2-mpm-prefork.
How can I really detach my children programs from apache?
edit
You can reproduce it on a Linux/Mac this way :
a) create a executed_script.php file that contains :
<?php
sleep(10);
b) create a execute_from_http.php file that contains :
<?php
exec("php executed_script.php > /tmp/test.log 2>&1 & echo -n \$!");
c) run http://localhost/path/execute_from_http.php
d) on a terminal, run the command :
ps axjf | grep execute | grep -v grep ; sudo /etc/init.d/apache2 restart ; ps axjf | grep execute | grep -v grep
If you run the command during the 10 secs of the execute_from_http.php script, you'll get the output :
php#beast:/var/www/xxx/$ ps axjf | grep execute | grep -v grep ; sudo /etc/init.d/apache2 restart ; ps axjf | grep execute | grep -v grep
1 5257 5245 5245 ? -1 S 33 0:00 php executed_script.php
* Restarting web server apache2
... waiting ...done.
php#beast:/var/www/xxx/$
As you can see, the ps command outputs only once, this tells you that the executed script died when apache restarted.
The "at" method
I found a working solution but I don't know if that's ok if we speak performance and security. It uses the at command, a kind of cron working only once.
Instead of :
exec("php executed_script.php > /dev/null 2>&1 & echo -n \$!");
Use :
exec("echo 'php executed_script.php > /dev/null 2>&1' | at now -M");
The key is that executed_script.php will be run by an external daemon (atd), so executed_script.php will be a child of atd and not an apache's one.
php#beast:/var/www/xxx$ ps axjf | grep execute | grep -v grep ; sudo /etc/init.d/apache2 restart ; ps axjf | grep execute | grep -v grep
7032 7033 973 973 ? -1 SN 33 0:00 \_ php executed_script.php
* Restarting web server apache2
... waiting ...done.
7032 7033 973 973 ? -1 SN 33 0:00 \_ php executed_script.php
php#beast:/var/www/xxx$ ps ax | grep 973
973 ? Ss 0:00 atd
Note several things :
you can't access the pid of your ran app, if you get $! like on my previous pieces of code, you'll get the pid of at.
you need to remove www-data which is by default in /etc/at.deny (it is probably there with reasons, so take care)
i have serious doubts about performance : I think that at write on a file read by atd to communicate
The fork / setsid method
As #hek2mgl wrote in its own answer, we can use a pcntl_fork(), but that's not as simple as that. First, you can't run pcntl_fork() behind apache, because if we look at the PHP Manual, Introduction of the Process Control, we can see:
Process Control should not be enabled within a web server environment
and unexpected results may happen if any Process Control functions are
used within a web server environment.
When a fork is made, you get two exact copy of the parent process in memory. And because PHP behind apache is run as a module, at the end of the PHP execution (even after a die()), you come back to the apache's module wrapper, and you can't control what's going on.
So here is the scenario with an intermediate command that will daemonize your execution:
1) From Apache, you run the intermediate command that will create your daemonized command :
$command = escapeshellarg("php executed_script.php");
exec("php run_as_daemon.php {$command} >> /dev/null 2>&1 &");
2) The intermediate command fork and use posix_setsid to really detach your command.
<?php
if (!isset($argv[1]))
{
exit;
}
$command = $argv[1];
$pid = pcntl_fork();
if ($pid < 0) // error
exit;
else if ($pid) // parent
exit;
else // child
{
$sid = posix_setsid(); // creates a daemon
if ($sid < 0)
exit;
exec("{$command} >> /dev/null 2>&1 &");
}
3) Your executed command, of course, doesn't change :
<?php
sleep(10);
Result :
php#beast:/var/www/xxx/$ wget -qO- http://localhost/xxx/execute_from_http.php && sleep 1 && ps axjf | grep execute | grep -v grep ; sudo /etc/init.d/apache2 restart ; ps axjf | grep execute | grep -v grep
1 19958 19956 19956 ? -1 S 33 0:00 php executed_script.php
* Restarting web server apache2 ......done.
1 19958 19956 19956 ? -1 S 33 0:00 php executed_script.php
First note, that the '&' in your example is just a boolean AND that concats the command and the echo. If you want to start the command in background, meaning that exec will return immediately, use the & at the very end of the command line:
exec("{$command} >> /tmp/test.log 2>&1 & echo -n \$! &");
If you want the process running after apache has finished you'll have to daemonize the process using pcntl_fork()
Here comes an example:
$pid = pcntl_fork();
switch($pid) {
case -1 : die ('Error while forking');
case 0: // daemon code
posix_setsid(); // create new process group
exec("{$command} >> /tmp/test.log 2>&1 & echo -n \$!");
break;
default:
echo 'daemon started';
break;
}
Now there is no code in the starting PHP scripts that handles the return value of exec nor its output. So the current process can finish before exec has finished. The worker process will be owned by init after this.
Also you can have a look at the PEAR package System_Daemon. This can help to daemonize a script.
I ran a php script, let's use "mytestscript.php" for example.
It will run continuously for a few hours. How can I stop it from the Terminal (UNIX) command line?
Assuming it's running in the background, under your user id: use ps to find the command's PID. Then use kill [PID] to stop it. If kill by itself doesn't do the job, do kill -9 [PID].
If it's running in the foreground, Ctrl-C (Control C) should stop it.
Read the documentation on the ps command and familiarize yourself with its options. It's a very useful command.
You can try using ps -e | grep php to find all processes that have 'php' in their name. After that, you can do kill <PID>, replacing <PID> with the number the ps command gave you.
If you want an automated solution try this -
1.Create a new shell script - vi killer.sh
2.Add the following
#!/bin/bash
while true
do
sleep $1
ps -ef | grep mytestscript.php | grep -v grep | awk '{print $2}' | xargs kill -9
done
3.Grant executable permissions chmod +x killer.sh
4.Execute your script as nohup ./killer.sh <time to sleep before killing> &
5.Leave it and go to the beach!
You can always find the process id of the running process. "ps -ef | grep mytestscript.php". Look at the output and note down pid of the process. use kill pid to kill the process.