CLI: Catching Ctrl+C, kill commands and fatal errors

Permanent Link: CLI: Catching Ctrl+C, kill commands and fatal errors 31. Mai 2009 RSS Feed for comments on RSS-Feed für Kommentare zu: CLI: Catching Ctrl+C, kill commands and fatal errors comments feed

Sometimes, when you write a Command Line (CLI) script, you want to catch Ctrl+C. Simple Example: Your script does some stuff on the database and you don't want to leave it in the state it had in the moment the script was killed, Ctrl+C'd or quit by a fatal error.

First off, we have to tell PHP to use ticks, in order for the catches to work (for more information on ticks check the pcntl_signal() documentation):

declare(ticks = 1);

Then, we add shutdown functions to the classes that have to rollback the state:

/**
* Cleanup if process has been killed unexpectedly
*
*/
private function shutdown()
{
$this->getTargetDb()->rollBack();
print('Script quit unexpectedly. Doing rollback' . PHP_EOL);
exit();
}

/**
* Method that is executed, when a Fatal Error occurs
*
*/
public function fatalErrorShutdown()
{
$lastError = error_get_last();
if (!is_null($lastError) && $lastError['type'] === E_ERROR) {
$this->shutdown();
}
}

/**
* Method, that is executed, if script has been killed by
* SIGINT: Ctrl+C
* SIGTERM: kill
*
* @param int $signal
*
*/
public function sigintShutdown($signal)
{
if ($signal === SIGINT || $signal === SIGTERM) {
$this->shutdown();
}
}

You shouldn't forget to include an exit() at some point in the shutdown methods or your script won't quit at all. In the example the shutdown() method (which is called by both shutdown methods, that will be registered afterwards) quits the script as soon as it's done.

As a last step, you only have to register your shutdown methods and you're done:

$sync = new Process_Sync();
// Catch Fatal Error (Rollback)
register_shutdown_function(array($sync, 'fatalErrorShutdown'));
// Catch Ctrl+C, kill and SIGTERM (Rollback)
pcntl_signal(SIGTERM, array($sync, 'sigintShutdown'));
pcntl_signal(SIGINT, array($sync, 'sigintShutdown'));

5 comments

Robert de Wildes Gravatar

Robert de Wilde
07.02.2010, 09:53 o'clock

This was great help, thanks! Only thing is that my exit() didn't seem to be right, lol. Can't kill the proces :)

Dominik Jungowskis Gravatar

Dominik Jungowski
07.02.2010, 20:05 o'clock

What does the script look like?


14.01.2011, 23:30 o'clock

Works great, thanks!

Geoffrey McRaes Gravatar

Geoffrey McRae
27.02.2011, 10:51 o'clock

Umm, why the class… you can just do this..

function catchSigInt() {
}

function catchSigTerm() {
}

pcntl_signal(SIGINT , 'catchSigInt' );
pcntl_signal(SIGTERM, 'catchSigTerm');

You should also be aware that "register_shutdown_function" doesn't just occur on a fatal shutdown, it occurs EVERY time your script exits.

IT support UKs Gravatar

IT support UK
23.10.2011, 11:21 o'clock

C has a numerical value of three. It was chosen to cause an interrupt as it is otherwise unlikely to be part of the program's interactive interface.

Write a comment

(will not be published)