private function updateAutoscale()

in src/daemon/PhutilDaemonPool.php [257:354]


  private function updateAutoscale() {
    if ($this->shouldShutdown()) {
      return;
    }

    // Don't try to autoscale more than once per second. This mostly stops the
    // logs from getting flooded in verbose mode.
    $now = time();
    if ($this->lastAutoscaleUpdate >= $now) {
      return;
    }
    $this->lastAutoscaleUpdate = $now;

    $daemons = $this->getDaemons();

    // If this pool is already at the maximum size, we can't launch any new
    // daemons.
    $max_size = $this->getPoolMaximumSize();
    if (count($daemons) >= $max_size) {
      $this->logMessage(
        'POOL',
        pht(
          'Autoscale pool "%s" already at maximum size (%s of %s).',
          $this->getPoolLabel(),
          new PhutilNumber(count($daemons)),
          new PhutilNumber($max_size)));
      return;
    }

    $scaleup_duration = $this->getPoolScaleupDuration();

    foreach ($daemons as $daemon) {
      $busy_epoch = $daemon->getBusyEpoch();
      // If any daemons haven't started work yet, don't scale the pool up.
      if (!$busy_epoch) {
        $this->logMessage(
          'POOL',
          pht(
            'Autoscale pool "%s" has an idle daemon, declining to scale.',
            $this->getPoolLabel()));
        return;
      }

      // If any daemons started work very recently, wait a little while
      // to scale the pool up.
      $busy_for = ($now - $busy_epoch);
      if ($busy_for < $scaleup_duration) {
        $this->logMessage(
          'POOL',
          pht(
            'Autoscale pool "%s" has not been busy long enough to scale up '.
            '(busy for %s of %s seconds).',
            $this->getPoolLabel(),
            new PhutilNumber($busy_for),
            new PhutilNumber($scaleup_duration)));
        return;
      }
    }

    // If we have a configured memory reserve for this pool, it tells us that
    // we should not scale up unless there's at least that much memory left
    // on the system (for example, a reserve of 0.25 means that 25% of system
    // memory must be free to autoscale).

    // Note that the first daemon is exempt: we'll always launch at least one
    // daemon, regardless of any memory reservation.
    if (count($daemons)) {
      $reserve = $this->getPoolMemoryReserve();
      if ($reserve) {
        // On some systems this may be slightly more expensive than other
        // checks, so we only do it once we're prepared to scale up.
        $memory = PhutilSystem::getSystemMemoryInformation();
        $free_ratio = ($memory['free'] / $memory['total']);

        // If we don't have enough free memory, don't scale.
        if ($free_ratio <= $reserve) {
          $this->logMessage(
            'POOL',
            pht(
              'Autoscale pool "%s" does not have enough free memory to '.
              'scale up (%s free of %s reserved).',
              $this->getPoolLabel(),
              new PhutilNumber($free_ratio, 3),
              new PhutilNumber($reserve, 3)));
          return;
        }
      }
    }

    $this->logMessage(
      'AUTO',
      pht(
        'Scaling pool "%s" up to %s daemon(s).',
        $this->getPoolLabel(),
        new PhutilNumber(count($daemons) + 1)));

    $this->newDaemon();
  }