Differential D20601 Diff 49167 src/applications/daemon/management/PhabricatorDaemonManagementWorkflow.php
Changeset View
Changeset View
Standalone View
Standalone View
src/applications/daemon/management/PhabricatorDaemonManagementWorkflow.php
| Show First 20 Lines • Show All 380 Lines • ▼ Show 20 Lines | final protected function executeStartCommand(array $options) { | ||||
| ); | ); | ||||
| $this->launchDaemons($daemons, $is_debug = false); | $this->launchDaemons($daemons, $is_debug = false); | ||||
| $console->writeErr("%s\n", pht('Done.')); | $console->writeErr("%s\n", pht('Done.')); | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| final protected function executeStopCommand( | final protected function executeStopCommand(array $options) { | ||||
| array $pids, | |||||
| array $options) { | |||||
| $console = PhutilConsole::getConsole(); | |||||
| $grace_period = idx($options, 'graceful', 15); | $grace_period = idx($options, 'graceful', 15); | ||||
| $force = idx($options, 'force'); | $force = idx($options, 'force'); | ||||
| $gently = idx($options, 'gently'); | |||||
| if ($gently && $force) { | $query = id(new PhutilProcessQuery()) | ||||
| throw new PhutilArgumentUsageException( | ->withIsOverseer(true); | ||||
| pht( | |||||
| 'You can not specify conflicting options %s and %s together.', | |||||
| '--gently', | |||||
| '--force')); | |||||
| } | |||||
| $daemons = $this->loadRunningDaemons(); | $instance = PhabricatorEnv::getEnvConfig('cluster.instance'); | ||||
| if (!$daemons) { | if ($instance !== null && !$force) { | ||||
| $survivors = array(); | $query->withInstances(array($instance)); | ||||
| if (!$pids && !$gently) { | |||||
| $survivors = $this->processRogueDaemons( | |||||
| $grace_period, | |||||
| $warn = true, | |||||
| $force); | |||||
| } | |||||
| if (!$survivors) { | |||||
| $console->writeErr( | |||||
| "%s\n", | |||||
| pht('There are no running Phabricator daemons.')); | |||||
| } | |||||
| return 0; | |||||
| } | } | ||||
| $stop_pids = $this->selectDaemonPIDs($daemons, $pids); | try { | ||||
| $process_refs = $query->execute(); | |||||
| } catch (Exception $ex) { | |||||
| // See T13321. If this fails for some reason, just continue for now so | |||||
| // that daemon management still works. In the long run, we don't expect | |||||
| // this to fail, but I don't want to break this workflow while we iron | |||||
| // bugs out. | |||||
| if (!$stop_pids) { | // See T12827. Particularly, this is likely to fail on Solaris. | ||||
| $console->writeErr("%s\n", pht('No daemons to kill.')); | |||||
| return 0; | |||||
| } | |||||
| $survivors = $this->sendStopSignals($stop_pids, $grace_period); | phlog($ex); | ||||
| // Try to clean up PID files for daemons we killed. | $process_refs = array(); | ||||
| $remove = array(); | |||||
| foreach ($daemons as $daemon) { | |||||
| $pid = $daemon->getPID(); | |||||
| if (empty($stop_pids[$pid])) { | |||||
| // We did not try to stop this overseer. | |||||
| continue; | |||||
| } | } | ||||
| if (isset($survivors[$pid])) { | if (!$process_refs) { | ||||
| // We weren't able to stop this overseer. | if ($instance !== null && !$force) { | ||||
amckinley: Don't you think we should distinguish between "no daemons found" and "we couldn't run the… | |||||
Done Inline ActionsWe'll still phlog($ex), so Solaris should get something like this: EXCEPTION: ps doesn't take these flags on solaris ha ha ha NO DAEMONS ...which should be reasonably clear, and if anyone hits this maybe we can write phutil_is_solaris() and find the right ps incantation on Solaris. On Windows I think we just fatal instantly anyway since there's no posix or pcntl. So, practically, I don't think any paths today will lead to messaging that just says "no stuff" when the root cause is really "ProcessQuery can't deal with it", although this is sort of a product of me arranging things to hit a convenient series of coincidences rather than an explicit rule of the system. epriestley: We'll still `phlog($ex)`, so Solaris should get something like this:
```
EXCEPTION: ps doesn't… | |||||
| continue; | $this->logInfo( | ||||
| pht('NO DAEMONS'), | |||||
| pht( | |||||
| 'There are no running daemons for the current instance ("%s"). '. | |||||
| 'Use "--force" to stop daemons for all instances.', | |||||
Not Done Inline Actions"for all instances" amckinley: "for all instances" | |||||
| $instance)); | |||||
| } else { | |||||
| $this->logInfo( | |||||
| pht('NO DAEMONS'), | |||||
| pht('There are no running daemons.')); | |||||
| } | } | ||||
| if (!$daemon->getPIDFile()) { | return 0; | ||||
| // We don't know where the PID file is. | |||||
| continue; | |||||
| } | } | ||||
| $remove[] = $daemon->getPIDFile(); | $process_refs = mpull($process_refs, null, 'getPID'); | ||||
| $stop_pids = array_keys($process_refs); | |||||
| $live_pids = $this->sendStopSignals($stop_pids, $grace_period); | |||||
| $stop_pids = array_fuse($stop_pids); | |||||
| $live_pids = array_fuse($live_pids); | |||||
| $dead_pids = array_diff_key($stop_pids, $live_pids); | |||||
| foreach ($dead_pids as $dead_pid) { | |||||
| $dead_ref = $process_refs[$dead_pid]; | |||||
| $this->logOkay( | |||||
| pht('STOP'), | |||||
| pht( | |||||
| 'Stopped PID %d ("%s")', | |||||
| $dead_pid, | |||||
| $dead_ref->getCommand())); | |||||
| } | } | ||||
| foreach (array_unique($remove) as $remove_file) { | foreach ($live_pids as $live_pid) { | ||||
| Filesystem::remove($remove_file); | $live_ref = $process_refs[$live_pid]; | ||||
| $this->logFail( | |||||
| pht('SURVIVED'), | |||||
| pht( | |||||
| 'Unable to stop PID %d ("%s").', | |||||
| $live_pid, | |||||
| $live_ref->getCommand())); | |||||
| } | } | ||||
| if (!$gently) { | if ($live_pids) { | ||||
| $this->processRogueDaemons($grace_period, !$pids, $force); | $this->logWarn( | ||||
| pht('SURVIVORS'), | |||||
| pht( | |||||
| 'Unable to stop all daemon processes. You may need to run this '. | |||||
| 'command as root with "sudo".')); | |||||
| } | } | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| final protected function executeReloadCommand(array $pids) { | final protected function executeReloadCommand(array $pids) { | ||||
| $console = PhutilConsole::getConsole(); | $console = PhutilConsole::getConsole(); | ||||
| Show All 18 Lines | foreach ($reload_pids as $pid) { | ||||
| "%s\n", | "%s\n", | ||||
| pht('Reloading process %d...', $pid)); | pht('Reloading process %d...', $pid)); | ||||
| posix_kill($pid, SIGHUP); | posix_kill($pid, SIGHUP); | ||||
| } | } | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| private function processRogueDaemons($grace_period, $warn, $force_stop) { | |||||
| $console = PhutilConsole::getConsole(); | |||||
| $rogue_daemons = PhutilDaemonOverseer::findRunningDaemons(); | |||||
| if ($rogue_daemons) { | |||||
| if ($force_stop) { | |||||
| $rogue_pids = ipull($rogue_daemons, 'pid'); | |||||
| $survivors = $this->sendStopSignals($rogue_pids, $grace_period); | |||||
| if ($survivors) { | |||||
| $console->writeErr( | |||||
| "%s\n", | |||||
| pht( | |||||
| 'Unable to stop processes running without PID files. '. | |||||
| 'Try running this command again with sudo.')); | |||||
| } | |||||
| } else if ($warn) { | |||||
| $console->writeErr("%s\n", $this->getForceStopHint($rogue_daemons)); | |||||
| } | |||||
| } | |||||
| return $rogue_daemons; | |||||
| } | |||||
| private function getForceStopHint($rogue_daemons) { | |||||
| $debug_output = ''; | |||||
| foreach ($rogue_daemons as $rogue) { | |||||
| $debug_output .= $rogue['pid'].' '.$rogue['command']."\n"; | |||||
| } | |||||
| return pht( | |||||
| "There are processes running that look like Phabricator daemons but ". | |||||
| "have no corresponding PID files:\n\n%s\n\n". | |||||
| "Stop these processes by re-running this command with the %s parameter.", | |||||
| $debug_output, | |||||
| '--force'); | |||||
| } | |||||
| private function sendStopSignals($pids, $grace_period) { | private function sendStopSignals($pids, $grace_period) { | ||||
| // If we're doing a graceful shutdown, try SIGINT first. | // If we're doing a graceful shutdown, try SIGINT first. | ||||
| if ($grace_period) { | if ($grace_period) { | ||||
| $pids = $this->sendSignal($pids, SIGINT, $grace_period); | $pids = $this->sendSignal($pids, SIGINT, $grace_period); | ||||
| } | } | ||||
| // If we still have daemons, SIGTERM them. | // If we still have daemons, SIGTERM them. | ||||
| if ($pids) { | if ($pids) { | ||||
| ▲ Show 20 Lines • Show All 139 Lines • Show Last 20 Lines | |||||
Don't you think we should distinguish between "no daemons found" and "we couldn't run the query"? If for no other reason than to more-quickly shake out weird distros where our ps invocation doesn't work. (Incidentally, it does work on my Mac, so hooray for that).