diff --git a/src/daemon/PhutilDaemon.php b/src/daemon/PhutilDaemon.php --- a/src/daemon/PhutilDaemon.php +++ b/src/daemon/PhutilDaemon.php @@ -47,6 +47,7 @@ const MESSAGETYPE_BUSY = 'busy'; const MESSAGETYPE_IDLE = 'idle'; const MESSAGETYPE_DOWN = 'down'; + const MESSAGETYPE_HIBERNATE = 'hibernate'; const WORKSTATE_BUSY = 'busy'; const WORKSTATE_IDLE = 'idle'; @@ -125,6 +126,35 @@ return $this->inGracefulShutdown; } + final protected function shouldHibernate($duration) { + // Don't hibernate if we don't have very long to sleep. + if ($duration < 5) { + return false; + } + + // Never hibernate if we're part of a pool and could scale down instead. + // We only hibernate the last process to drop the pool size to zero. + if ($this->getScaledownDuration()) { + return false; + } + + // Don't hibernate for too long. + $duration = max($duration, phutil_units('3 minutes in seconds')); + + $this->emitOverseerMessage( + self::MESSAGETYPE_HIBERNATE, + array( + 'duration' => $duration, + )); + + $this->log( + pht( + 'Preparing to hibernate for %s second(s).', + new PhutilNumber($duration))); + + return true; + } + final protected function sleep($duration) { $this->notifyReceived = false; $this->willSleep($duration); diff --git a/src/daemon/PhutilDaemonHandle.php b/src/daemon/PhutilDaemonHandle.php --- a/src/daemon/PhutilDaemonHandle.php +++ b/src/daemon/PhutilDaemonHandle.php @@ -192,8 +192,18 @@ } private function scheduleRestart() { - $this->logMessage('WAIT', pht('Waiting to restart process.')); - $this->restartAt = time() + self::getWaitBeforeRestart(); + // Wait a minimum of a few sceconds before restarting, but we may wait + // longer if the daemon has initiated hibernation. + $default_restart = time() + self::getWaitBeforeRestart(); + if ($default_restart >= $this->restartAt) { + $this->restartAt = $default_restart; + } + + $this->logMessage( + 'WAIT', + pht( + 'Waiting %s second(s) to restart process.', + new PhutilNumber($this->restartAt - time()))); } /** @@ -352,6 +362,16 @@ $this->shouldRestart = false; $this->shouldShutdown = true; break; + case PhutilDaemon::MESSAGETYPE_HIBERNATE: + $config = idx($structure, 1); + $duration = (int)idx($config, 'duration', 0); + $this->restartAt = time() + $duration; + $this->logMessage( + 'ZZZZ', + pht( + 'Process is preparing to hibernate for %s second(s).', + new PhutilNumber($duration))); + break; default: // If we can't parse this or it isn't a message we understand, just // emit the raw message.