Changeset View
Changeset View
Standalone View
Standalone View
src/infrastructure/daemon/PhutilDaemonOverseer.php
| Show All 26 Lines | final class PhutilDaemonOverseer extends Phobject { | ||||
| const SIGNAL_RELOAD = 'signal/reload'; | const SIGNAL_RELOAD = 'signal/reload'; | ||||
| const SIGNAL_GRACEFUL = 'signal/graceful'; | const SIGNAL_GRACEFUL = 'signal/graceful'; | ||||
| const SIGNAL_TERMINATE = 'signal/terminate'; | const SIGNAL_TERMINATE = 'signal/terminate'; | ||||
| private $err = 0; | private $err = 0; | ||||
| private $inAbruptShutdown; | private $inAbruptShutdown; | ||||
| private $inGracefulShutdown; | private $inGracefulShutdown; | ||||
| private $futurePool; | |||||
| public function __construct(array $argv) { | public function __construct(array $argv) { | ||||
| PhutilServiceProfiler::getInstance()->enableDiscardMode(); | PhutilServiceProfiler::getInstance()->enableDiscardMode(); | ||||
| $args = new PhutilArgumentParser($argv); | $args = new PhutilArgumentParser($argv); | ||||
| $args->setTagline(pht('daemon overseer')); | $args->setTagline(pht('daemon overseer')); | ||||
| $args->setSynopsis(<<<EOHELP | $args->setSynopsis(<<<EOHELP | ||||
| **launch_daemon.php** [__options__] __daemon__ | **launch_daemon.php** [__options__] __daemon__ | ||||
| Launch and oversee an instance of __daemon__. | Launch and oversee an instance of __daemon__. | ||||
| ▲ Show 20 Lines • Show All 112 Lines • ▼ Show 20 Lines | EOHELP | ||||
| public function addLibrary($library) { | public function addLibrary($library) { | ||||
| $this->libraries[] = $library; | $this->libraries[] = $library; | ||||
| return $this; | return $this; | ||||
| } | } | ||||
| public function run() { | public function run() { | ||||
| $this->createDaemonPools(); | $this->createDaemonPools(); | ||||
| $future_pool = $this->getFuturePool(); | |||||
| while (true) { | while (true) { | ||||
| if ($this->shouldReloadDaemons()) { | if ($this->shouldReloadDaemons()) { | ||||
| $this->didReceiveSignal(SIGHUP); | $this->didReceiveSignal(SIGHUP); | ||||
| } | } | ||||
| $futures = array(); | |||||
| $running_pools = false; | $running_pools = false; | ||||
| foreach ($this->getDaemonPools() as $pool) { | foreach ($this->getDaemonPools() as $pool) { | ||||
| $pool->updatePool(); | $pool->updatePool(); | ||||
| if (!$this->shouldShutdown()) { | if (!$this->shouldShutdown()) { | ||||
| if ($pool->isHibernating()) { | if ($pool->isHibernating()) { | ||||
| if ($this->shouldWakePool($pool)) { | if ($this->shouldWakePool($pool)) { | ||||
| $pool->wakeFromHibernation(); | $pool->wakeFromHibernation(); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| foreach ($pool->getFutures() as $future) { | foreach ($pool->getFutures() as $future) { | ||||
| $futures[] = $future; | $future_pool->addFuture($future); | ||||
| } | } | ||||
| if ($pool->getDaemons()) { | if ($pool->getDaemons()) { | ||||
| $running_pools = true; | $running_pools = true; | ||||
| } | } | ||||
| } | } | ||||
| $this->updateMemory(); | $this->updateMemory(); | ||||
| $this->waitForDaemonFutures($futures); | if ($future_pool->hasFutures()) { | ||||
| $future_pool->resolve(); | |||||
| } else { | |||||
| if (!$this->shouldShutdown()) { | |||||
| sleep(1); | |||||
| } | |||||
| } | |||||
| if (!$futures && !$running_pools) { | if (!$future_pool->hasFutures() && !$running_pools) { | ||||
| if ($this->shouldShutdown()) { | if ($this->shouldShutdown()) { | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| exit($this->err); | exit($this->err); | ||||
| } | } | ||||
| private function getFuturePool() { | |||||
| if (!$this->futurePool) { | |||||
| $pool = new FuturePool(); | |||||
| // TODO: This only wakes if any daemons actually exit, or 1 second | |||||
| // passes. It would be a bit cleaner to wait on any I/O, but Futures | |||||
| // currently can't do that. | |||||
| private function waitForDaemonFutures(array $futures) { | $pool->getIteratorTemplate() | ||||
| assert_instances_of($futures, 'ExecFuture'); | |||||
| if ($futures) { | |||||
| // TODO: This only wakes if any daemons actually exit. It would be a bit | |||||
| // cleaner to wait on any I/O with Channels. | |||||
| $iter = id(new FutureIterator($futures)) | |||||
| ->setUpdateInterval(1); | ->setUpdateInterval(1); | ||||
| foreach ($iter as $future) { | |||||
| break; | $this->futurePool = $pool; | ||||
| } | |||||
| } else { | |||||
| if (!$this->shouldShutdown()) { | |||||
| sleep(1); | |||||
| } | |||||
| } | } | ||||
| return $this->futurePool; | |||||
| } | } | ||||
| private function createDaemonPools() { | private function createDaemonPools() { | ||||
| $configs = $this->config['daemons']; | $configs = $this->config['daemons']; | ||||
| $forced_options = array( | $forced_options = array( | ||||
| 'load' => $this->libraries, | 'load' => $this->libraries, | ||||
| 'log' => $this->log, | 'log' => $this->log, | ||||
| ▲ Show 20 Lines • Show All 176 Lines • Show Last 20 Lines | |||||