Skip to content

Plugins

Jason M edited this page Jun 7, 2017 · 4 revisions

Synopsis

Plugins provide a standard way to inject custom code into the Daemon w/o having to modify any Daemon code directly. Some Plugins may provide public methods that your Daemon code can use to perform different functions. Or a Plugin might provide no public methods and instead can listen to Events and do things behind-the-scenes. Or maybe do both.

A simple PluginInterface is defined that you must implement to make a Plugin. Any public methods you define will be available to the calling code as usual. All calls to plugin methods are done in the current process and are not forked.

namespace Lifo\Daemon\Plugin;
interface PluginInterface
{
    /**
     * Initial setup of plugin. Perform all one-time setup steps needed for the plugin.
     *
     * @param array $options Array of custom options
     */
    public function setup($options = []);

    /**
     * Teardown the plugin. Release all resources created during the plugins lifetime.
     */
    public function teardown();
}

AbstractPlugin

A special AbstractPlugin class is available to extend that adds a little extra magic to your Plugin and makes it even easier to create a custom Plugin.

  • Automatically adds your Plugin to the Daemon::stats() output via the DaemonEvent::ON_STATS event.
  • Implements ArrayAccess for your Plugin so your code can access the Plugin options via array access: $plugin['option'].

Using Plugins

Using a Plugin is easy. First add it to your Daemon in the Daemon::initialize method. You can add a plugin in different ways:

  • A class instance. EG: new MyPlugin()
  • A class name (as a string). When passed as a FQCN string plugins can be lazily loaded. Meaning, they will not actually be created until the first time you use the plugin.
class MyDaemon extends Daemon {
  public function initialize() {
    // creates a plugin named 'file_lock'. Uses the base name of the class, converted to "snake_case".
    $this->addPlugin('Lifo\Daemon\Plugin\FileLock');

    // creates a plugin named 'custom' with some options
    $this->addPlugin(new MyPlugin(), 'custom', [
      'option1' => 'hello',
      'option2' => 'World',
    ]);

    // creates a plugin named 'special' with no options that will be lazily loaded
    $this->addPlugin('My\Plugin\SpecialPlugin', 'special', [], false);
  }
}

Once a Plugin is created you can use it in your code by calling Daemon::plugin with the name you created it with. The plugin returned by this method will be your real Plugin class, with no wrapper.

class MyDaemon extends Daemon {
  public function execute() {
    // get plugin reference
    $plugin = $this->plugin('special');
    // you can call any methods on the plugin. Assume the 'SpecialPlugin' has the method below.
    $plugin->doSomething(new Date());
  }

  public function initialize() {
    // see code block above
  }
}

Plugin Scope

All plugins are available to all children Tasks and Workers you create. It's sometimes important to make sure your plugin understands what scope it's in so it doesn't do something it shouldn't. The scope is going to be either parent or child. If you use a plugin in your main Daemon code then you're in the parent. Otherwise, if you use a plugin from any Task or Worker then you're be in a forked child. You can tell what scope you're in by calling:

  • Daemon::isParent()

It's important to understand that Plugins do not share state between forked processes. If a Worker uses a plugin to do something and then stores a value in the plugin, another Worker will not have the same state on that same plugin.

Plugin Life Time

Plugins will be available during the entire life cycle of your daemon. Even when the Daemon is in shutdown mode. All plugins will be garbage collected when the daemon completes it's shutdown procedure.