<?php

/**
 * Overseer modules allow daemons to be externally influenced.
 *
 * See @{class:PhabricatorDaemonOverseerModule} for a concrete example.
 */
abstract class PhutilDaemonOverseerModule extends Phobject {


  /**
   * This method is used to indicate to the overseer that daemons should reload.
   *
   * @return bool  True if the daemons should reload, otherwise false.
   */
  abstract public function shouldReloadDaemons();


  /**
   * Should a hibernating daemon pool be awoken immediately?
   *
   * @return bool True to awaken the pool immediately.
   */
  public function shouldWakePool(PhutilDaemonPool $pool) {
    return false;
  }


  public static function getAllModules() {
    return id(new PhutilClassMapQuery())
      ->setAncestorClass(__CLASS__)
      ->execute();
  }

}

<?php

/**
 * Overseer modules allow daemons to be externally influenced.
 *
 * See @{class:PhabricatorDaemonOverseerModule} for a concrete example.
 */
abstract class PhutilDaemonOverseerModule extends Phobject {

  private $throttles = array();


  /**
   * This method is used to indicate to the overseer that daemons should reload.
   *
   * @return bool  True if the daemons should reload, otherwise false.
   */
  public function shouldReloadDaemons() {
    return false;
  }


  /**
   * Should a hibernating daemon pool be awoken immediately?
   *
   * @return bool True to awaken the pool immediately.
   */
  public function shouldWakePool(PhutilDaemonPool $pool) {
    return false;
  }


  public static function getAllModules() {
    return id(new PhutilClassMapQuery())
      ->setAncestorClass(__CLASS__)
      ->execute();
  }


  /**
   * Throttle checks from executing too often.
   *
   * If you throttle a check like this, it will only execute once every 2.5
   * seconds:
   *
   *   if ($this->shouldThrottle('some.check', 2.5)) {
   *     return;
   *   }
   *
   * @param string Throttle key.
   * @param float Duration in seconds.
   * @return bool True to throttle the check.
   */
  protected function shouldThrottle($name, $duration) {
    $throttle = idx($this->throttles, $name, 0);
    $now = microtime(true);

    // If not enough time has elapsed, throttle the check.
    $elapsed = ($now - $throttle);
    if ($elapsed < $duration) {
      return true;
    }

    // Otherwise, mark the current time as the last time we ran the check,
    // then let it continue.
    $this->throttles[$name] = $now;

    return false;
  }

}

Clean up overseer modules slightly and provide a throttling support method
Clean up overseer modules slightly and provide a throttling support method

Summary:
Ref T12298. Make it slightly easier to write overseer modules:

  - You don't need to implement shouldReloadDaemons(), since you can now just implement shouldWakePool() and get useful behavior.
  - It looks like most modules want to do checks only every X seconds, where X is at least somewhat module/use-case dependent, so add a helper for that.

Test Plan: Ran `bin/phd debug pull --trace`, saw config check fire properly every 10 seconds after updating it to use `shouldThrottle()` in the next change.

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T12298

Differential Revision: https://secure.phabricator.com/D17539
