-
Notifications
You must be signed in to change notification settings - Fork 15
Daemon
The abstract Daemon
class is the entry point for any daemon you want to create. It provides a Fluent Interface to allow for easier configuration and is a Singleton so only one daemon instance can be used in an application.
User code only has to implement the execute
method in order to have a fully working Daemon. Below is an example of a bare bones daemon. You can run this snippet in the root of your application (where composer.json
is).
Pressing ^C will exit the daemon.
require __DIR__ . '/vendor/autoload.php';
// needed for signal handling (so ^C will be captured and exit the daemon)
declare(ticks = 1);
class MyDaemon extends \Lifo\Daemon\Daemon
{
// execute will be called every loop cycle (1 second by default)
protected function execute()
{
$this->log("Daemon Loop %d", $this->getLoopIterations());
}
}
// run the daemon (`setVerbose` is called so we can see something for the test)
MyDaemon::getInstance()->setVerbose(true)->run();
Expected output from the above example daemon (The header row below was manually added to explain what each column is and you won't see that in the output of the daemon):
PARENT CHILD
TIMESTAMP PID PID MESSAGE
2017-05-30 15:04:44.7415: 5453 5453: Daemon Loop 1
2017-05-30 15:04:45.7414: 5453 5453: Daemon Loop 2
2017-05-30 15:04:46.7414: 5453 5453: Daemon Loop 3
The output above shows two different PID's. This is because the main daemon process (the parent) and any children Workers or Tasks can also output to the log. When a child emits a log message it's PID will be different than of the parent. This makes it easier to determine what is doing what in a multi-processing daemon.
The Daemon has many configuration methods available to change it's behavior. A Fluent Interface makes it easier for you to configure your daemon before calling run()
.
Some examples (not an exhaustive list):
-
setDaemonize(true)
- Toggle "daemon" mode (fork into the background) for the main process. -
setLoopInterval(x)
- Change the loop interval. -
setLogFile('daemon.log')
- Set log destination. -
setAutoRestartInterval(3600)
- Set auto-restart. -
setDebug(true)
- Enable debugging mode. -
setDebugLevel(3)
- Set debugging level. - ... etc ...
Any custom configuration you want to set must be done before you call the run()
method.
When the run()
method is called on your daemon a couple of things happen before the main daemon Event Loop actually starts.
-
Daemon::validateEnvironment()
is called. The environment is checked for dependencies. Such as, making sure the PCNTL extension is available, etc. - If
Daemon::$daemonize
isTRUE
then the daemon will fork into the background. -
Daemon::setupSignals()
is called. The daemon will now catch all available signals. User-land code should never callpcntl_signal()
to catch signals. Instead, you should listen for theDaemonEvents::ON_SIGNAL
event by callingDaemon::on(DaemonEvents::ON_SIGNAL, callable)
. -
Daemon::initialize()
is called (by default it does nothing). Your daemon can optionally override this method to add your own custom initialization. This is where you would setup any Plugins, Workers or Event handlers. Or, any other initialization that is required for your daemon. -
DaemonEvent::ON_INIT
event is dispatched. This event mainly allows Plugins to do their own initialization when the daemon is initialized. User-land code can also listen for this event and do extra initialization, but there's no reason to do that since you can override theinitialize()
method. - The main Event Loop starts up and your
execute()
will get called every loop cycle.