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

2 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?

Write a comment

(will not be published)