-
Notifications
You must be signed in to change notification settings - Fork 15
Signal Handling
The core Daemon class will automatically catch all known signals once it is initialized (call run()
).
User code should never call pcntl_signal()
to capture your own signals. You will override the signal handler that the Daemon sets up already for you. For example, if you override the SIGCHLD
signal, you'll completely break the ProcessManager and you'll end up with zombie processes and potentially stuck Workers.
For more information on what events you can capture in your Daemon, see Events.
To capture any signal within your application you should listen for the DaemonEvent::ON_SIGNAL
event. See the example below:
use Lifo\Daemon\Daemon;
use Lifo\Daemon\Event\DaemonEvent;
use Lifo\Daemon\Event\SignalEvent;
class MyDaemon extends Daemon {
private $signals = [];
protected function initialize() {
$this->on(DaemonEvent::ON_SIGNAL, function(SignalEvent $e) {
// this callback should do as little as possible!
$this->signals[] = $e->getSignal();
});
}
protected function execute() {
if ($this->signals) {
$this->log("Hey! I caught %d signal%s: %s. Isn't that wonderful?!",
count($this->signals),
count($this->signals) == 1 ? '' : 's',
implode(', ', $this->signals));
$this->signals = [];
}
}
}
In order for signal handling to work in ANY PHP script, you must declare how frequently ticks are captured by PHP. See the PHP documentation on declare(ticks=n) for more information.
The declare(ticks=1)
statement should be in the top most script for your application. If you call ./start_daemon.php
to start your daemon then the declare statement should be in the start_daemon.php
file.
The value for ticks
can be any value you want. The lower the value then the less delay signal handling will have, but more CPU will be taken up by the PHP process. Generally speaking, in my experience using declare(ticks=1)
works in almost all cases. Set, test and tweak...
Your signal callback is a special case where you need to do as little as possible. Signals are non reentrant. Meaning, once a signal is caught, that signal will not be caught again until your callback finishes.
Normally, you'll simply catch a signal, set a flag and then at the next loop iteration you should act on that flag and then reset the flag. So you're ready to catch the next signal. If your loop interval is set really high (5+ seconds) you may have a noticeable delay in your application in catching signals. So, plan and test properly.