Differential D20601 Diff 49136 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 DEAMONS'), | |||||
pht( | |||||
'There are no running daemons for the current instance ("%s"). '. | |||||
'Use "--force" to stop daemons for any instance.', | |||||
Not Done Inline Actions"for all instances" amckinley: "for all instances" | |||||
$instance)); | |||||
} else { | |||||
$this->logInfo( | |||||
pht('NO DEAMONS'), | |||||
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).