Is there a way I can automatically restart a PHP script whenever it exits, regardless of whether it has been exited properly, or has terminated due to an error, or maxed memory usage, etc.?
-
1put it in an infinite do while loop in a shell script? – Jesus Ramos Mar 21 '12 at 04:02
-
It might work but I have to have 8 threads of one script running at the same time, and all restarting themselves if they exit. So then I'd need 8 shell script running, right? It doesn't seem very efficient. – Alasdair Mar 21 '12 at 04:08
-
PHP script can be executed only if it is called. So using php only there is no way as i Think. But a background process can do this. If you can write such a background process which can check for running process & do the required steps, you can do it. – Sumant Mar 21 '12 at 04:17
-
1I have found [supervisord](http://supervisord.org) very useful for this purpose. You *could* implement such process supervision/control/restarting/daemon behavior in pure PHP, but why not use something that already exists? – deceze Mar 21 '12 at 04:18
-
php daemons are never very reliable. but I have used a cron job to check every 5 minutes and restart if necessary. If you can live with a 1 minute of downtime, try cron. – Mar 21 '12 at 04:28
-
I can live with that, but how is it going to know that there is only 7 instances of a single php script running instead of 8? – Alasdair Mar 21 '12 at 09:09
-
windows or *nix ? on nix you can use ps – Mar 21 '12 at 19:17
-
supervisord specifically supports keeping a specified number of instances up and running... :) – deceze Mar 22 '12 at 01:17
-
I don't understand the supervisord documentation. Could you please explain to me how to make it run multiple instances of the same PHP script and auto-restart them if any exit? Also, I need it to stagger the initial launch of each of the 8 instances by 1 minute between each. – Alasdair Mar 22 '12 at 05:22
8 Answers
A PHP Script can also restart itself with PCNTL.
Disclaimer: the point of this exercise is only to prove that PHP is perfectly capable of restarting itself and to answer the question:
Is there a way I can automatically restart a PHP script whenever it exits, regardless of whether it has been exited properly, or has terminated due to an error?
It is therefor beyond our scope to go into any detail about unix processes so I would suggest you start with the PCNTL book or refer to php-pcntl for more details. Developer discretion is required, just because we can, doesn't mean it's sensible. With all seriousness aside lets have some fun.
In the examples we will assume it is a PHP CLI script launched in a *nix environment from a terminal with a semi-decent shell using the command:
$ php i-can-restart-myself.php 0
We pass a restart count attribute as indicator that the process was restarted.
Can I automatically restart a PHP Script?
Yes I can!
<?php
echo ++$argv[1]; // count every restart
$_ = $_SERVER['_']; // or full path to php binary
echo "\n======== start =========\n";
// do a lot of stuff
$cnt = 0;
while( $cnt++ < 10000000 ){}
echo "\n========== end =========\n";
// restart myself
pcntl_exec($_, $argv);
Regardless of whether it has been terminated properly?
Yes I can restart if terminated!
<?php
echo ++$argv[1];
$_ = $_SERVER['_'];
register_shutdown_function(function () {
global $_, $argv; // note we need to reference globals inside a function
// restart myself
pcntl_exec($_, $argv);
});
echo "\n======== start =========\n";
// do a lot of stuff
$cnt = 0;
while( $cnt++ < 10000000 ){}
echo "\n========== end =========\n";
die; // exited properly
// we can't reach here
pcntl_exec($_, $argv);
Or terminated due to an error?
Ditto!
<?php
echo ++$argv[1];
$_ = $_SERVER['_'];
register_shutdown_function(function () {
global $_, $argv;
// restart myself
pcntl_exec($_, $argv);
});
echo "\n======== start =========\n";
// do a lot of stuff
$cnt = 0;
while( $cnt++ < 10000000 ){}
echo "\n===== what if? =========\n";
require 'OOPS! I dont exist.'; // FATAL Error:
// we can't reach here
echo "\n========== end =========\n";
die; // exited properly
// we can't reach here
pcntl_exec($_, $argv);
But you know I am going to want more than that right?
Certainly! I can restart on signals kill, hub, and even Ctrl-C!
<?php
echo ++$argv[1];
$_ = $_SERVER['_'];
$restartMyself = function () {
global $_, $argv;
pcntl_exec($_, $argv);
};
register_shutdown_function($restartMyself);
pcntl_signal(SIGTERM, $restartMyself); // kill
pcntl_signal(SIGHUP, $restartMyself); // kill -s HUP or kill -1
pcntl_signal(SIGINT, $restartMyself); // Ctrl-C
echo "\n======== start =========\n";
// do a lot of stuff
$cnt = 0;
while( $cnt++ < 10000000 ){}
echo "\n===== what if? =========\n";
require 'OOPS! I dont exist.'; // FATAL Error:
// we can't reach here
echo "\n========== end =========\n";
die; // exited properly
// we can't reach here
pcntl_exec($_, $argv);
How do I terminate it now?
If you flood the process by holding down Ctrl-C you might just catch it somewhere in the shutdown.
I don't want to see all these errors can I restart on those too?
No problem I can handle errors too!
<?php
echo ++$argv[1];
$_ = $_SERVER['_'];
$restartMyself = function () {
global $_, $argv;
pcntl_exec($_, $argv);
// NOTE: consider fork and exiting here as error handler
};
register_shutdown_function($restartMyself);
pcntl_signal(SIGTERM, $restartMyself);
pcntl_signal(SIGHUP, $restartMyself);
pcntl_signal(SIGINT, $restartMyself);
set_error_handler($restartMyself , E_ALL); // Catch all errors
echo "\n======== start =========\n";
// do a lot of stuff
$cnt = 0;
while( $cnt++ < 10000000 ){}
echo $CAREFUL_NOW; // NOTICE: will also be caught
// we would normally still go here
echo "\n===== what if? =========\n";
require 'OOPS! I dont exist.'; // FATAL Error:
// we can't reach here
echo "\n========== end =========\n";
die; // exited properly
// we can't reach here
pcntl_exec($_, $argv);
Although this appears to be working fine at first glance, because pcntl_exec
runs in the same process we do not notice that things are terribly wrong. If you wanted to spawn a new process and letting the old one die instead, which is a perfectly viable alternative see next post, you will find 2 processes are started each iteration, because we trigger a PHP NOTICE and an ERROR due to a common oversight. This can easily be rectified by ensuring we die()
or exit()
after the call to pcntl_exec
, since implementing an error handler PHP assumes tolerance were accepted and continues running. Narrowing the error reporting level instead of catching E_ALL
will be more responsible as well.
The point I am trying to make is that even if you are able to relaunch a script that failed this is not an excuse to allow broken code. Although there may exist viable use cases for this practice, I strongly disagree that restart on failure should be employed as a solution for scripts failing due to errors! As we can see from these examples there is no way of knowing exactly where it failed so we cant be sure where it will start from again. Going for the "quick fix" solution which could appear to be working fine may have more problems now then before.
I would instead prefer to see the defect addressed with some proper unit tests which will help flush out the culprit so we may rectify the problem. If PHP runs out of memory it can be avoided through conservative use of resources by unsetting the variables after use. (btw. you will find assigning null is much quicker than using unset for the same result) I am afraid though, if left unresolved, restarting would most definitely serve as suitable opener to the can of worms you already have.

- 8,417
- 4
- 42
- 56
-
1This did work for me however I had to pass the filepath directly in the second argument or the process just sat doing nothing (as if calling php with no file). I went ahead and directly passed the PHP path as well for good measure: pcntl_exec( '/usr/local/bin/php', [ \_\_FILE\_\_ ] ); – Jesse Oct 16 '18 at 13:03
-
-
1@MarcoMarsala It references a shell variable `$_` indicating the last executable file, in our case it is the full path to the PHP interpreter binary eg. `/usr/bin/php` and `$argv` contains all the arguments passed to `$_`, so `pcntl_exec($_, $argv)` is in effect the same as typing `php i-can-restart-myself.php 1` on the command line. – nickl- Oct 28 '22 at 09:00
Here be dragons.
Advanced usage and not for the faint of heart.
To launch a separate process change the restartMyself
function to include a pcntl_fork()
call, which according to the manual spawns a new process with an unique PID
, and we only restart the script as the child process. We then cleanly terminate the current process on handling the first error (the PHP WARNING), releasing resources and preventing execution to continue, also triggering the ERROR, and starting yet another process.
A basic multi-process restartMyself
function:
<?php
$restartMyself = function () {
global $_, $argv;
if(!pcntl_fork()) // We only care about the child fork
pcntl_exec($_, $argv);
die; // insist that we don't tolerate errors
};
Unfortunately this still gets us into a lot of trouble spawning multiple processes running in parallel with the same restart id, because if we try to exit the script in an error or signal handler it will trigger the registered shutdown function and fork another process. Only the exit call from within the shutdown function finally stops the process.
This can certainly be an adventure, chasing processes that restart themselves, immune to your kill attempts, if you do manage to catch them in process. =)
Make sure that the script has enough to do so you may have enough time to kill it.
To insist the undead stay dead, try:
$ kill -9 [PID]
or:
$ kill -s KILL [PID]
Making no idle reference to the undead as you would be wise to consider zombies and orphans but ultimately even the toughest processes usually still need a parent so killing the shell session should see them to rest.
Jokes aside, this is a valid use case which will optimally clear resources by destroying the old process and starting anew. Being reasonable you would of course leave yourself options to kill a process, as those signals (like SIGTERM
, SIGHUP
) are generally speaking on demand and intends to terminate, not expecting respawns, which may even be considered malicious to ignore.
All standard disclaimers apply... blah... blah...
To ensure that we only ever restart the script once, and in so doing will only ever have a single process running for a given script's execution, we will need to track the process id (PID) globally.
The complete single-process forked self restarting script:
<?php
echo ++$argv[1]; // count every restart with argument 1
$_ = $_SERVER['_']; // full path to PHP interpreter binary
$restartMyself = function () {
global $_, $argv, $pid; // track PID in global scope
if(!$pid ??= pcntl_fork()) // only fork if $pid is null
pcntl_exec($_, $argv); // only restart as the child fork
die; // exit parent process when called in shutdown function
};
register_shutdown_function($restartMyself);// catch on exit
pcntl_signal(SIGTERM, $restartMyself); // catch kill
pcntl_signal(SIGHUP, $restartMyself); // catch kill -s HUP or kill -1
pcntl_signal(SIGINT, $restartMyself); // catch Ctrl-C
set_error_handler($restartMyself , E_ALL); // catch all errors
// do a lot of stuff
for ($cnt = 0; $cnt++ < 999999999;){}
echo $UNDEFINED_VAR; // WARNING: will be caught,
// script restarted as new process,
// and current process terminated
// we will not reach here anymore
Run the script in any *nix compatible environment using:
$ php i-can-respawn-myself.php 0
nJoy!

- 8,417
- 4
- 42
- 56
Assuming:
- Call the same script file x number of times
- Re-call if it gets interrupted/ended/stopped
- Automated process for infinite loop
Some options come to mind to achieve your goal [Unix/Linux based solutions]:
Use a BASH script, so that the PHP script can be resumed after it stopped/ended/interrupted:
#!/bin/bash clear date php -f my_php_file.php sleep 100 # rerun myself exec $0
The Fat Controller execution handler, these are the key features you're looking for:
- Used to repeatedly run other programs
- Can run many instances of any script/program in parallel
- Any script can be rerun once it finishes executing
Very similar to CRON but the key features are just what you need
Using CRON, you can have it call your PHP script at intervals of e.g. every minute, then with this code at the very beginning of you PHP script, you will be able to control the number of processes running, exiting if there are already 8:
exec('ps -A | grep ' . escapeshellarg(basename(__FILE__)) , $results); if (count($results) > 7) { echo "8 Already Running\n" die(0); }
Search for processes running with the same path of the current file, and returns the number of processes found, if bigger than 7, exit.
-
Updated the answer with practical tested solutions for your goal (unix/linux) based solutions. – Zuul Jul 02 '12 at 07:42
Using CRON
#!/bin/sh
process = 'script.php'
if ps ax | grep -v grep | grep $process
then
echo "$process is running..."
else
echo "$process not running, relaunching..."
php /your/php/script.php
fi

- 1,704
- 1
- 22
- 15
To complement ow3n's answer, a PHP CLI script is like any other command, and can be easily repeated in an infinite while
loop. It will work the exact same as running the command by itself, but will run again when it ends. Just hit Ctrl+C when you want to terminate the loop.
Edit: If your process catches signals (which it should if it's a 12 factor app), you will need to hold Ctrl+C instead of just pressing it. A press would be caught by the process (which should terminate itself), but the while
loop would restart the process again (which is be useful if you just want to restart the process instead of terminating it). If your process is not catching signals, then Ctrl+C will kill both the process and the while
loop.
Here is the simplest way to do so, without any extra output:
while :; do [command]; done
while :; do echo "test" && sleep 1; done
while :; do php myscript.php; done
That said, I am a bit worried about the implications in your comments:
About threads:
- I would think twice about using threads in PHP. Languages that use that model have a much better/stable/mature environment than PHP does (Java, for example).
- Using multiple processes instead of multiple threads might seem inefficient, but trust me, it more than makes it up in terms of simplicity, maintainability, ease of debugging, etc. Multithreading can quickly lead you to maintenance hell, which explains the emergence of the Actor Model.
- Is efficiency a business requirement? That's usually due to limited resources (things like embedded devices), but I doubt that's your case, otherwise you wouldn't be using PHP. Consider that, nowadays, people are much more expensive than computers. Therefore, to minimize cost, it's much more beneficial to maximize the efficiency of your people, not your computers (see the Unix philosophy's Rule of Economy). Multithreading, if done well, will save you some money by optimizing the usage of your computers, but will cost you much more in terms of the headaches it will cause for your people.
- If you absolutely have to use threads, I would strongly urge you to consider the Actor model. Akka is a great implementation.
About processes:
- If you are running your scripts in development, one process [of each type] should be enough.
- If you are running your scripts in production, you should rely on a process manager to manage your processes, such as Upstart.
- Avoid turning your processes into deamons.
- Learn about 12 factor applications, especially processes, concurrency & disposability.
Update: Containers make running & managing a fleet of processes even easier.
Just my 5 cents: a PCNTL restart with custom error handling implementation.
register_shutdown_function("shutdownHandler");
function shutdownHandler() { // will be called when php script ends.
$lasterror = error_get_last();
switch ($lasterror['type']) {
case E_ERROR:
case E_CORE_ERROR:
case E_COMPILE_ERROR:
case E_USER_ERROR:
case E_RECOVERABLE_ERROR:
case E_CORE_WARNING:
case E_COMPILE_WARNING:
case E_PARSE:
$error = "[SHUTDOWN] lvl:" . $lasterror['type'] .
" | msg:" . $lasterror['message'] .
" | file:" . $lasterror['file'] .
" | ln:" . $lasterror['line'];
myCustomLogHandler("FATAL EXIT $error\n");
}
$_ = $_SERVER['_'];
global $_;
pcntl_exec($_);
}

- 8,417
- 4
- 42
- 56

- 1,307
- 15
- 19
-
1
-
Not all these error constants are fatal meaning that they won't trigger a shutdown, consider registering the error handler section with `set_error_handler` instead. – nickl- Jun 23 '22 at 03:08
To restart a script every time it stops running you can wrap user1179181's script in a loop.
#!/bin/bash
while true
do
if ps ax | grep -v grep | grep "script.php"
then
echo "process is running..."
else
clear
date
echo "process not running, relaunching..."
php script.php
fi
sleep 10
done