Skip to content
This repository has been archived by the owner on Jan 5, 2022. It is now read-only.
shaneharter edited this page May 20, 2012 · 20 revisions

PHP Daemon Implementation Q&A

Versions: 1.1, 2.0

What Do I Do First?

The Example daemon in /App uses a config.php file that defines an autoloader and other settings. The other important file in the /App directory is error_handlers.php. You can use whatever error handling strategy you'd like, as long as you include an error handler, an uncaught exception handler, and a shutdown function. The point here is that errors do happen and we want to use all the tools PHP gives us to manage error conditions.

From there, if you look at the Example daemon you'll get a quick idea of all you need to do to write a daemon. Specifically:

Set protected/public variables

The PHP Simple Daemon way is to set these in your class definition. Your daemon class will not need a __construct method.

  1. $loop_interval

    If you're building a server or using a blocking api in your event loop like socket_listen or LibEvent, you should omit this.

    How often (in seconds) should your execute() method be called. For example, if you want to do something every second, or every 5 seconds, or every 60 seconds. If your execute() method takes longer than $loop_interval to return, an error will be logged. If you want execute() to be called as soon as the previous call finished, you can set $loop_interval=0.

  2. $auto_restart_interval How often (in seconds) should the daemon restart itself? This will only be activated if you run in daemon mode (-d at the commandline.) If you omit, the daemon will restart every 24 hours.

  3. $install_instructions This is an array of plain-text instructions that will be displayed when you pass -i at the command prompt. Gives administrators and other users the information they may need to run your daemon. Optional, but encouraged.

     protected $install_instructions = array (
                   'Create /var/log/mydaemon directory with 0755 with write access for the daemon',
                   'Setup sendmail'
                   'Update config.ini with production database credentials'
               )
    

Create a load_plugins Method

  • Use this method to setup any plugins. Most often, this will at least be a Lock plugin. You can choose one of the Lock providers in the /Lock directory or write your own that extends the Core_Lock_Lock class. They are used to prevent more than one instance of your daemon from running at any given time.

  • You may also want to write your own plugins. It's an easy way to re-use code and it allows you to tie-in to the daemon state events like setup, teardown, etc.

Create a load_workers Method

  • Use this method to setup any workers. See related documentation for the Workers API.

Create a setup Method

  • The base class defines an abstract setup() method so you have to create it. But it can be empty.
  • If your daemon uses database connections, listens to message queues, etc, this is where you should set that all up.

Create an execute Method

  • This is where you begin your application. The actual work of your daemon begins here. In most of our production daemons, we use many classes and libraries, and the execute() method is just a few lines to bootstrap and run them.

  • NOTE: If you've developed a daemon before, you know that you begin with a while(true) event loop. This is why your application stays running. You stop it by interrupting the loop with a kill signal, or a break statement. Remember that PHP Simple Daemon implements the event loop for you. Your execute() method is called inside this event loop at whatever frequency you specify using the $loop_interval setting.

  • If you set $loop_interval=0 or omit it altogether, your daemon will pause for just a fraction of a second in between execute() calls to manage events and defer to the Kernel scheduler. Alternatively, if you do set an interval, be sure to design your execute() method to complete in that allotted time. You may need to use parallel processing if you have a longer running task, by using a Worker or passing a callback to the fork() method.

  • Alternatively, you could keep your execute() method empty to satisfy the Abstract base class, and instead using the ON_RUN event to hook your application code into the event loop.

How Can I Control the Event Loop?

You have several options to control/break the event loop from your application code.

  • Graceful Shutdown. When a kill [pid] signal is sent to your daemon, it will do a graceful shutdown: It will finish the current iteration of the while() loop, run its destructors, run teardown() on all loaded plugins, and exit cleanly. Any forked child processes will finish their work and exit. You can also initiate this in your code by calling $this->shutdown(true).

  • Exception. You can throw an exception from within execute() that will be caught outside the run loop and will trigger a fatal error. In daemon-mode, the system will attempt to recover by restarting the daemon on your behalf.

  • You can manipulate the loop frequency. You can change the $loop_interval while the daemon is running using the loop_interval() method.

Clone this wiki locally