mirror of
https://we.phorge.it/source/phorge.git
synced 2025-01-07 13:21:02 +01:00
(stable) Promote 2019 Week 26
This commit is contained in:
commit
4c242256e4
10 changed files with 202 additions and 455 deletions
|
@ -10,7 +10,7 @@ return array(
|
|||
'conpherence.pkg.css' => '3c8a0668',
|
||||
'conpherence.pkg.js' => '020aebcf',
|
||||
'core.pkg.css' => 'af983028',
|
||||
'core.pkg.js' => '8225dc58',
|
||||
'core.pkg.js' => '5a792749',
|
||||
'differential.pkg.css' => '8d8360fb',
|
||||
'differential.pkg.js' => '67e02996',
|
||||
'diffusion.pkg.css' => '42c75c37',
|
||||
|
@ -253,7 +253,7 @@ return array(
|
|||
'rsrc/externals/javelin/lib/URI.js' => '2e255291',
|
||||
'rsrc/externals/javelin/lib/Vector.js' => 'e9c80beb',
|
||||
'rsrc/externals/javelin/lib/WebSocket.js' => 'fdc13e4e',
|
||||
'rsrc/externals/javelin/lib/Workflow.js' => '851f642d',
|
||||
'rsrc/externals/javelin/lib/Workflow.js' => '445e21a8',
|
||||
'rsrc/externals/javelin/lib/__tests__/Cookie.js' => 'ca686f71',
|
||||
'rsrc/externals/javelin/lib/__tests__/DOM.js' => '4566e249',
|
||||
'rsrc/externals/javelin/lib/__tests__/JSON.js' => '710377ae',
|
||||
|
@ -752,7 +752,7 @@ return array(
|
|||
'javelin-workboard-header' => '111bfd2d',
|
||||
'javelin-workboard-header-template' => 'ebe83a6b',
|
||||
'javelin-workboard-order-template' => '03e8891f',
|
||||
'javelin-workflow' => '851f642d',
|
||||
'javelin-workflow' => '445e21a8',
|
||||
'maniphest-report-css' => '3d53188b',
|
||||
'maniphest-task-edit-css' => '272daa84',
|
||||
'maniphest-task-summary-css' => '61d1667e',
|
||||
|
@ -1294,6 +1294,17 @@ return array(
|
|||
'43bc9360' => array(
|
||||
'javelin-install',
|
||||
),
|
||||
'445e21a8' => array(
|
||||
'javelin-stratcom',
|
||||
'javelin-request',
|
||||
'javelin-dom',
|
||||
'javelin-vector',
|
||||
'javelin-install',
|
||||
'javelin-util',
|
||||
'javelin-mask',
|
||||
'javelin-uri',
|
||||
'javelin-routable',
|
||||
),
|
||||
'46116c01' => array(
|
||||
'javelin-request',
|
||||
'javelin-behavior',
|
||||
|
@ -1607,17 +1618,6 @@ return array(
|
|||
'javelin-resource',
|
||||
'javelin-routable',
|
||||
),
|
||||
'851f642d' => array(
|
||||
'javelin-stratcom',
|
||||
'javelin-request',
|
||||
'javelin-dom',
|
||||
'javelin-vector',
|
||||
'javelin-install',
|
||||
'javelin-util',
|
||||
'javelin-mask',
|
||||
'javelin-uri',
|
||||
'javelin-routable',
|
||||
),
|
||||
'87428eb2' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-diffusion-locate-file-source',
|
||||
|
|
|
@ -536,6 +536,9 @@ final class PhabricatorExtraConfigSetupCheck extends PhabricatorSetupCheck {
|
|||
|
||||
'differential.whitespace-matters' => pht(
|
||||
'Whitespace rendering is now handled automatically.'),
|
||||
|
||||
'phd.pid-directory' => pht(
|
||||
'Phabricator daemons no longer use PID files.'),
|
||||
);
|
||||
|
||||
return $ancient_config;
|
||||
|
|
|
@ -21,10 +21,6 @@ final class PhabricatorPHDConfigOptions
|
|||
|
||||
public function getOptions() {
|
||||
return array(
|
||||
$this->newOption('phd.pid-directory', 'string', '/var/tmp/phd/pid')
|
||||
->setLocked(true)
|
||||
->setDescription(
|
||||
pht('Directory that phd should use to track running daemons.')),
|
||||
$this->newOption('phd.log-directory', 'string', '/var/tmp/phd/log')
|
||||
->setLocked(true)
|
||||
->setDescription(
|
||||
|
|
|
@ -6,7 +6,10 @@ final class PhabricatorDaemonManagementRestartWorkflow
|
|||
protected function didConstruct() {
|
||||
$this
|
||||
->setName('restart')
|
||||
->setSynopsis(pht('Stop, then start the standard daemon loadout.'))
|
||||
->setSynopsis(
|
||||
pht(
|
||||
'Stop daemon processes on this host, then start the standard '.
|
||||
'daemon loadout.'))
|
||||
->setArguments(
|
||||
array(
|
||||
array(
|
||||
|
@ -17,17 +20,15 @@ final class PhabricatorDaemonManagementRestartWorkflow
|
|||
'seconds. Defaults to __15__ seconds.'),
|
||||
'default' => 15,
|
||||
),
|
||||
array(
|
||||
'name' => 'gently',
|
||||
'help' => pht(
|
||||
'Ignore running processes that look like daemons but do not '.
|
||||
'have corresponding PID files.'),
|
||||
),
|
||||
array(
|
||||
'name' => 'force',
|
||||
'help' => pht(
|
||||
'Also stop running processes that look like daemons but do '.
|
||||
'not have corresponding PID files.'),
|
||||
'Stop all daemon processes on this host, even if they belong '.
|
||||
'to another Phabricator instance.'),
|
||||
),
|
||||
array(
|
||||
'name' => 'gently',
|
||||
'help' => pht('Deprecated. Has no effect.'),
|
||||
),
|
||||
$this->getAutoscaleReserveArgument(),
|
||||
));
|
||||
|
@ -35,12 +36,11 @@ final class PhabricatorDaemonManagementRestartWorkflow
|
|||
|
||||
public function execute(PhutilArgumentParser $args) {
|
||||
$err = $this->executeStopCommand(
|
||||
array(),
|
||||
array(
|
||||
'graceful' => $args->getArg('graceful'),
|
||||
'force' => $args->getArg('force'),
|
||||
'gently' => $args->getArg('gently'),
|
||||
));
|
||||
|
||||
if ($err) {
|
||||
return $err;
|
||||
}
|
||||
|
|
|
@ -6,101 +6,52 @@ final class PhabricatorDaemonManagementStatusWorkflow
|
|||
protected function didConstruct() {
|
||||
$this
|
||||
->setName('status')
|
||||
->setSynopsis(pht('Show status of running daemons.'))
|
||||
->setArguments(
|
||||
array(
|
||||
array(
|
||||
'name' => 'local',
|
||||
'help' => pht('Show only local daemons.'),
|
||||
),
|
||||
));
|
||||
->setSynopsis(pht('Show daemon processes on this host.'));
|
||||
}
|
||||
|
||||
public function execute(PhutilArgumentParser $args) {
|
||||
$console = PhutilConsole::getConsole();
|
||||
$process_refs = $this->getOverseerProcessRefs();
|
||||
|
||||
if ($args->getArg('local')) {
|
||||
$daemons = $this->loadRunningDaemons();
|
||||
} else {
|
||||
$daemons = $this->loadAllRunningDaemons();
|
||||
}
|
||||
if (!$process_refs) {
|
||||
$instance = $this->getInstance();
|
||||
if ($instance !== null) {
|
||||
$this->logInfo(
|
||||
pht('NO DAEMONS'),
|
||||
pht(
|
||||
'There are no running daemon processes for the current '.
|
||||
'instance ("%s").',
|
||||
$instance));
|
||||
} else {
|
||||
$this->writeInfo(
|
||||
pht('NO DAEMONS'),
|
||||
pht('There are no running daemon processes.'));
|
||||
}
|
||||
|
||||
if (!$daemons) {
|
||||
$console->writeErr(
|
||||
"%s\n",
|
||||
pht('There are no running Phabricator daemons.'));
|
||||
return 1;
|
||||
}
|
||||
|
||||
$status = 0;
|
||||
|
||||
$table = id(new PhutilConsoleTable())
|
||||
->addColumns(array(
|
||||
'id' => array(
|
||||
'title' => pht('Log'),
|
||||
),
|
||||
'daemonID' => array(
|
||||
'title' => pht('Daemon'),
|
||||
),
|
||||
'host' => array(
|
||||
'title' => pht('Host'),
|
||||
),
|
||||
'pid' => array(
|
||||
'title' => pht('Overseer'),
|
||||
),
|
||||
'started' => array(
|
||||
'title' => pht('Started'),
|
||||
),
|
||||
'daemon' => array(
|
||||
'title' => pht('Class'),
|
||||
),
|
||||
'argv' => array(
|
||||
'title' => pht('Arguments'),
|
||||
),
|
||||
));
|
||||
|
||||
foreach ($daemons as $daemon) {
|
||||
if ($daemon instanceof PhabricatorDaemonLog) {
|
||||
$table->addRow(array(
|
||||
'id' => $daemon->getID(),
|
||||
'daemonID' => $daemon->getDaemonID(),
|
||||
'host' => $daemon->getHost(),
|
||||
'pid' => $daemon->getPID(),
|
||||
'started' => date('M j Y, g:i:s A', $daemon->getDateCreated()),
|
||||
'daemon' => $daemon->getDaemon(),
|
||||
'argv' => csprintf('%LR', $daemon->getExplicitArgv()),
|
||||
->addColumns(
|
||||
array(
|
||||
'pid' => array(
|
||||
'title' => pht('PID'),
|
||||
),
|
||||
'command' => array(
|
||||
'title' => pht('Command'),
|
||||
),
|
||||
));
|
||||
} else if ($daemon instanceof PhabricatorDaemonReference) {
|
||||
$name = $daemon->getName();
|
||||
if (!$daemon->isRunning()) {
|
||||
$daemon->updateStatus(PhabricatorDaemonLog::STATUS_DEAD);
|
||||
$status = 2;
|
||||
$name = pht('<DEAD> %s', $name);
|
||||
}
|
||||
|
||||
$daemon_log = $daemon->getDaemonLog();
|
||||
$id = null;
|
||||
$daemon_id = null;
|
||||
if ($daemon_log) {
|
||||
$id = $daemon_log->getID();
|
||||
$daemon_id = $daemon_log->getDaemonID();
|
||||
}
|
||||
|
||||
$table->addRow(array(
|
||||
'id' => $id,
|
||||
'daemonID' => $daemon_id,
|
||||
'host' => 'localhost',
|
||||
'pid' => $daemon->getPID(),
|
||||
'started' => $daemon->getEpochStarted()
|
||||
? date('M j Y, g:i:s A', $daemon->getEpochStarted())
|
||||
: null,
|
||||
'daemon' => $name,
|
||||
'argv' => csprintf('%LR', $daemon->getArgv()),
|
||||
foreach ($process_refs as $process_ref) {
|
||||
$table->addRow(
|
||||
array(
|
||||
'pid' => $process_ref->getPID(),
|
||||
'command' => $process_ref->getCommand(),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
$table->draw();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -6,11 +6,7 @@ final class PhabricatorDaemonManagementStopWorkflow
|
|||
protected function didConstruct() {
|
||||
$this
|
||||
->setName('stop')
|
||||
->setSynopsis(
|
||||
pht(
|
||||
'Stop all running daemons, or specific daemons identified by PIDs. '.
|
||||
'Use **%s** to find PIDs.',
|
||||
'phd status'))
|
||||
->setSynopsis(pht('Stop daemon processes on this host.'))
|
||||
->setArguments(
|
||||
array(
|
||||
array(
|
||||
|
@ -24,29 +20,21 @@ final class PhabricatorDaemonManagementStopWorkflow
|
|||
array(
|
||||
'name' => 'force',
|
||||
'help' => pht(
|
||||
'Also stop running processes that look like daemons but do '.
|
||||
'not have corresponding PID files.'),
|
||||
'Stop all daemon processes on this host, even if they belong '.
|
||||
'to another Phabricator instance.'),
|
||||
),
|
||||
array(
|
||||
'name' => 'gently',
|
||||
'help' => pht(
|
||||
'Ignore running processes that look like daemons but do not '.
|
||||
'have corresponding PID files.'),
|
||||
),
|
||||
array(
|
||||
'name' => 'pids',
|
||||
'wildcard' => true,
|
||||
'help' => pht('Deprecated. Has no effect.'),
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
public function execute(PhutilArgumentParser $args) {
|
||||
return $this->executeStopCommand(
|
||||
$args->getArg('pids'),
|
||||
array(
|
||||
'graceful' => $args->getArg('graceful'),
|
||||
'force' => $args->getArg('force'),
|
||||
'gently' => $args->getArg('gently'),
|
||||
));
|
||||
}
|
||||
|
||||
|
|
|
@ -12,11 +12,6 @@ abstract class PhabricatorDaemonManagementWorkflow
|
|||
->selectSymbolsWithoutLoading();
|
||||
}
|
||||
|
||||
final protected function getPIDDirectory() {
|
||||
$path = PhabricatorEnv::getEnvConfig('phd.pid-directory');
|
||||
return $this->getControlDirectory($path);
|
||||
}
|
||||
|
||||
final protected function getLogDirectory() {
|
||||
$path = PhabricatorEnv::getEnvConfig('phd.log-directory');
|
||||
return $this->getControlDirectory($path);
|
||||
|
@ -30,56 +25,16 @@ abstract class PhabricatorDaemonManagementWorkflow
|
|||
pht(
|
||||
"%s requires the directory '%s' to exist, but it does not exist ".
|
||||
"and could not be created. Create this directory or update ".
|
||||
"'%s' / '%s' in your configuration to point to an existing ".
|
||||
"'%s' in your configuration to point to an existing ".
|
||||
"directory.",
|
||||
'phd',
|
||||
$path,
|
||||
'phd.pid-directory',
|
||||
'phd.log-directory'));
|
||||
}
|
||||
}
|
||||
return $path;
|
||||
}
|
||||
|
||||
final protected function loadRunningDaemons() {
|
||||
$daemons = array();
|
||||
|
||||
$pid_dir = $this->getPIDDirectory();
|
||||
$pid_files = Filesystem::listDirectory($pid_dir);
|
||||
|
||||
foreach ($pid_files as $pid_file) {
|
||||
$path = $pid_dir.'/'.$pid_file;
|
||||
$daemons[] = PhabricatorDaemonReference::loadReferencesFromFile($path);
|
||||
}
|
||||
|
||||
return array_mergev($daemons);
|
||||
}
|
||||
|
||||
final protected function loadAllRunningDaemons() {
|
||||
$local_daemons = $this->loadRunningDaemons();
|
||||
|
||||
$local_ids = array();
|
||||
foreach ($local_daemons as $daemon) {
|
||||
$daemon_log = $daemon->getDaemonLog();
|
||||
|
||||
if ($daemon_log) {
|
||||
$local_ids[] = $daemon_log->getID();
|
||||
}
|
||||
}
|
||||
|
||||
$daemon_query = id(new PhabricatorDaemonLogQuery())
|
||||
->setViewer(PhabricatorUser::getOmnipotentUser())
|
||||
->withStatus(PhabricatorDaemonLogQuery::STATUS_ALIVE);
|
||||
|
||||
if ($local_ids) {
|
||||
$daemon_query->withoutIDs($local_ids);
|
||||
}
|
||||
|
||||
$remote_daemons = $daemon_query->execute();
|
||||
|
||||
return array_merge($local_daemons, $remote_daemons);
|
||||
}
|
||||
|
||||
private function findDaemonClass($substring) {
|
||||
$symbols = $this->loadAvailableDaemonClasses();
|
||||
|
||||
|
@ -169,7 +124,7 @@ abstract class PhabricatorDaemonManagementWorkflow
|
|||
$flags[] = '--verbose';
|
||||
}
|
||||
|
||||
$instance = PhabricatorEnv::getEnvConfig('cluster.instance');
|
||||
$instance = $this->getInstance();
|
||||
if ($instance) {
|
||||
$flags[] = '-l';
|
||||
$flags[] = $instance;
|
||||
|
@ -185,14 +140,6 @@ abstract class PhabricatorDaemonManagementWorkflow
|
|||
$config['log'] = $this->getLogDirectory().'/daemons.log';
|
||||
}
|
||||
|
||||
$pid_dir = $this->getPIDDirectory();
|
||||
|
||||
// TODO: This should be a much better user experience.
|
||||
Filesystem::assertExists($pid_dir);
|
||||
Filesystem::assertIsDirectory($pid_dir);
|
||||
Filesystem::assertWritable($pid_dir);
|
||||
|
||||
$config['piddir'] = $pid_dir;
|
||||
$config['daemons'] = $daemons;
|
||||
|
||||
$command = csprintf('./phd-daemon %Ls', $flags);
|
||||
|
@ -324,28 +271,31 @@ abstract class PhabricatorDaemonManagementWorkflow
|
|||
$console = PhutilConsole::getConsole();
|
||||
|
||||
if (!idx($options, 'force')) {
|
||||
$running = $this->loadRunningDaemons();
|
||||
$process_refs = $this->getOverseerProcessRefs();
|
||||
if ($process_refs) {
|
||||
$this->logWarn(
|
||||
pht('RUNNING DAEMONS'),
|
||||
pht('Daemons are already running:'));
|
||||
|
||||
// This may include daemons which were launched but which are no longer
|
||||
// running; check that we actually have active daemons before failing.
|
||||
foreach ($running as $daemon) {
|
||||
if ($daemon->isRunning()) {
|
||||
$message = pht(
|
||||
"phd start: Unable to start daemons because daemons are already ".
|
||||
"running.\n\n".
|
||||
"You can view running daemons with '%s'.\n".
|
||||
"You can stop running daemons with '%s'.\n".
|
||||
"You can use '%s' to stop all daemons before starting ".
|
||||
"new daemons.\n".
|
||||
"You can force daemons to start anyway with %s.",
|
||||
'phd status',
|
||||
'phd stop',
|
||||
'phd restart',
|
||||
'--force');
|
||||
|
||||
$console->writeErr("%s\n", $message);
|
||||
exit(1);
|
||||
fprintf(STDERR, '%s', "\n");
|
||||
foreach ($process_refs as $process_ref) {
|
||||
fprintf(
|
||||
STDERR,
|
||||
'%s',
|
||||
tsprintf(
|
||||
" %s %s\n",
|
||||
$process_ref->getPID(),
|
||||
$process_ref->getCommand()));
|
||||
}
|
||||
fprintf(STDERR, '%s', "\n");
|
||||
|
||||
$this->logFail(
|
||||
pht('RUNNING DAEMONS'),
|
||||
pht(
|
||||
'Use "phd stop" to stop daemons, "phd restart" to restart '.
|
||||
'daemons, or "phd start --force" to ignore running processes.'));
|
||||
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -386,148 +336,115 @@ abstract class PhabricatorDaemonManagementWorkflow
|
|||
return 0;
|
||||
}
|
||||
|
||||
final protected function executeStopCommand(
|
||||
array $pids,
|
||||
array $options) {
|
||||
|
||||
$console = PhutilConsole::getConsole();
|
||||
|
||||
final protected function executeStopCommand(array $options) {
|
||||
$grace_period = idx($options, 'graceful', 15);
|
||||
$force = idx($options, 'force');
|
||||
$gently = idx($options, 'gently');
|
||||
|
||||
if ($gently && $force) {
|
||||
throw new PhutilArgumentUsageException(
|
||||
$query = id(new PhutilProcessQuery())
|
||||
->withIsOverseer(true);
|
||||
|
||||
$instance = $this->getInstance();
|
||||
if ($instance !== null && !$force) {
|
||||
$query->withInstances(array($instance));
|
||||
}
|
||||
|
||||
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.
|
||||
|
||||
// See T12827. Particularly, this is likely to fail on Solaris.
|
||||
|
||||
phlog($ex);
|
||||
|
||||
$process_refs = array();
|
||||
}
|
||||
|
||||
if (!$process_refs) {
|
||||
if ($instance !== null && !$force) {
|
||||
$this->logInfo(
|
||||
pht('NO DAEMONS'),
|
||||
pht(
|
||||
'There are no running daemons for the current instance ("%s"). '.
|
||||
'Use "--force" to stop daemons for all instances.',
|
||||
$instance));
|
||||
} else {
|
||||
$this->logInfo(
|
||||
pht('NO DAEMONS'),
|
||||
pht('There are no running daemons.'));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
$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(
|
||||
'You can not specify conflicting options %s and %s together.',
|
||||
'--gently',
|
||||
'--force'));
|
||||
'Stopped PID %d ("%s")',
|
||||
$dead_pid,
|
||||
$dead_ref->getCommand()));
|
||||
}
|
||||
|
||||
$daemons = $this->loadRunningDaemons();
|
||||
if (!$daemons) {
|
||||
$survivors = array();
|
||||
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;
|
||||
foreach ($live_pids as $live_pid) {
|
||||
$live_ref = $process_refs[$live_pid];
|
||||
$this->logFail(
|
||||
pht('SURVIVED'),
|
||||
pht(
|
||||
'Unable to stop PID %d ("%s").',
|
||||
$live_pid,
|
||||
$live_ref->getCommand()));
|
||||
}
|
||||
|
||||
$stop_pids = $this->selectDaemonPIDs($daemons, $pids);
|
||||
|
||||
if (!$stop_pids) {
|
||||
$console->writeErr("%s\n", pht('No daemons to kill.'));
|
||||
return 0;
|
||||
}
|
||||
|
||||
$survivors = $this->sendStopSignals($stop_pids, $grace_period);
|
||||
|
||||
// Try to clean up PID files for daemons we killed.
|
||||
$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])) {
|
||||
// We weren't able to stop this overseer.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!$daemon->getPIDFile()) {
|
||||
// We don't know where the PID file is.
|
||||
continue;
|
||||
}
|
||||
|
||||
$remove[] = $daemon->getPIDFile();
|
||||
}
|
||||
|
||||
foreach (array_unique($remove) as $remove_file) {
|
||||
Filesystem::remove($remove_file);
|
||||
}
|
||||
|
||||
if (!$gently) {
|
||||
$this->processRogueDaemons($grace_period, !$pids, $force);
|
||||
if ($live_pids) {
|
||||
$this->logWarn(
|
||||
pht('SURVIVORS'),
|
||||
pht(
|
||||
'Unable to stop all daemon processes. You may need to run this '.
|
||||
'command as root with "sudo".'));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
final protected function executeReloadCommand(array $pids) {
|
||||
$console = PhutilConsole::getConsole();
|
||||
$process_refs = $this->getOverseerProcessRefs();
|
||||
|
||||
if (!$process_refs) {
|
||||
$this->logInfo(
|
||||
pht('NO DAEMONS'),
|
||||
pht('There are no running daemon processes to reload.'));
|
||||
|
||||
$daemons = $this->loadRunningDaemons();
|
||||
if (!$daemons) {
|
||||
$console->writeErr(
|
||||
"%s\n",
|
||||
pht('There are no running daemons to reload.'));
|
||||
return 0;
|
||||
}
|
||||
|
||||
$reload_pids = $this->selectDaemonPIDs($daemons, $pids);
|
||||
if (!$reload_pids) {
|
||||
$console->writeErr(
|
||||
"%s\n",
|
||||
pht('No daemons to reload.'));
|
||||
return 0;
|
||||
}
|
||||
foreach ($process_refs as $process_ref) {
|
||||
$pid = $process_ref->getPID();
|
||||
|
||||
foreach ($reload_pids as $pid) {
|
||||
$console->writeOut(
|
||||
"%s\n",
|
||||
$this->logInfo(
|
||||
pht('RELOAD'),
|
||||
pht('Reloading process %d...', $pid));
|
||||
|
||||
posix_kill($pid, SIGHUP);
|
||||
}
|
||||
|
||||
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) {
|
||||
// If we're doing a graceful shutdown, try SIGINT first.
|
||||
if ($grace_period) {
|
||||
|
@ -674,4 +591,21 @@ abstract class PhabricatorDaemonManagementWorkflow
|
|||
return $select_pids;
|
||||
}
|
||||
|
||||
protected function getOverseerProcessRefs() {
|
||||
$query = id(new PhutilProcessQuery())
|
||||
->withIsOverseer(true);
|
||||
|
||||
$instance = PhabricatorEnv::getEnvConfig('cluster.instance');
|
||||
if ($instance !== null) {
|
||||
$query->withInstances(array($instance));
|
||||
}
|
||||
|
||||
return $query->execute();
|
||||
}
|
||||
|
||||
protected function getInstance() {
|
||||
return PhabricatorEnv::getEnvConfig('cluster.instance');
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -1375,16 +1375,16 @@ abstract class PhabricatorApplicationTransaction
|
|||
|
||||
public function getActionStrength() {
|
||||
if ($this->isInlineCommentTransaction()) {
|
||||
return 250;
|
||||
return 25;
|
||||
}
|
||||
|
||||
switch ($this->getTransactionType()) {
|
||||
case PhabricatorTransactions::TYPE_COMMENT:
|
||||
return 500;
|
||||
return 50;
|
||||
case PhabricatorTransactions::TYPE_SUBSCRIBERS:
|
||||
if ($this->isSelfSubscription()) {
|
||||
// Make this weaker than TYPE_COMMENT.
|
||||
return 250;
|
||||
return 25;
|
||||
}
|
||||
|
||||
if ($this->isApplicationAuthor()) {
|
||||
|
@ -1396,14 +1396,14 @@ abstract class PhabricatorApplicationTransaction
|
|||
// In other cases, subscriptions are more interesting than comments
|
||||
// (which are shown anyway) but less interesting than any other type of
|
||||
// transaction.
|
||||
return 750;
|
||||
return 75;
|
||||
case PhabricatorTransactions::TYPE_MFA:
|
||||
// We want MFA signatures to render at the top of transaction groups,
|
||||
// on top of the things they signed.
|
||||
return 10000;
|
||||
return 1000;
|
||||
}
|
||||
|
||||
return 1000;
|
||||
return 100;
|
||||
}
|
||||
|
||||
public function isCommentTransaction() {
|
||||
|
|
|
@ -1,128 +1,10 @@
|
|||
<?php
|
||||
|
||||
// TODO: See T13321. After the removal of daemon PID files this class
|
||||
// no longer makes as much sense as it once did.
|
||||
|
||||
final class PhabricatorDaemonReference extends Phobject {
|
||||
|
||||
private $name;
|
||||
private $argv;
|
||||
private $pid;
|
||||
private $start;
|
||||
private $pidFile;
|
||||
|
||||
private $daemonLog;
|
||||
|
||||
public static function loadReferencesFromFile($path) {
|
||||
$pid_data = Filesystem::readFile($path);
|
||||
|
||||
try {
|
||||
$dict = phutil_json_decode($pid_data);
|
||||
} catch (PhutilJSONParserException $ex) {
|
||||
$dict = array();
|
||||
}
|
||||
|
||||
$refs = array();
|
||||
$daemons = idx($dict, 'daemons', array());
|
||||
|
||||
$logs = array();
|
||||
|
||||
$daemon_ids = ipull($daemons, 'id');
|
||||
if ($daemon_ids) {
|
||||
try {
|
||||
$logs = id(new PhabricatorDaemonLogQuery())
|
||||
->setViewer(PhabricatorUser::getOmnipotentUser())
|
||||
->withDaemonIDs($daemon_ids)
|
||||
->execute();
|
||||
} catch (AphrontQueryException $ex) {
|
||||
// Ignore any issues here; getting this information only allows us
|
||||
// to provide a more complete picture of daemon status, and we want
|
||||
// these commands to work if the database is inaccessible.
|
||||
}
|
||||
|
||||
$logs = mpull($logs, null, 'getDaemonID');
|
||||
}
|
||||
|
||||
// Support PID files that use the old daemon format, where each overseer
|
||||
// had exactly one daemon. We can eventually remove this; they will still
|
||||
// be stopped by `phd stop --force` even if we don't identify them here.
|
||||
if (!$daemons && idx($dict, 'name')) {
|
||||
$daemons = array(
|
||||
array(
|
||||
'config' => array(
|
||||
'class' => idx($dict, 'name'),
|
||||
'argv' => idx($dict, 'argv', array()),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
foreach ($daemons as $daemon) {
|
||||
$ref = new PhabricatorDaemonReference();
|
||||
|
||||
// NOTE: This is the overseer PID, not the actual daemon process PID.
|
||||
// This is correct for checking status and sending signals (the only
|
||||
// things we do with it), but might be confusing. $daemon['pid'] has
|
||||
// the daemon PID, and we could expose that if we had some use for it.
|
||||
|
||||
$ref->pid = idx($dict, 'pid');
|
||||
$ref->start = idx($dict, 'start');
|
||||
|
||||
$config = idx($daemon, 'config', array());
|
||||
$ref->name = idx($config, 'class');
|
||||
$ref->argv = idx($config, 'argv', array());
|
||||
|
||||
$log = idx($logs, idx($daemon, 'id'));
|
||||
if ($log) {
|
||||
$ref->daemonLog = $log;
|
||||
}
|
||||
|
||||
$ref->pidFile = $path;
|
||||
$refs[] = $ref;
|
||||
}
|
||||
|
||||
return $refs;
|
||||
}
|
||||
|
||||
public function updateStatus($new_status) {
|
||||
if (!$this->daemonLog) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
$this->daemonLog
|
||||
->setStatus($new_status)
|
||||
->save();
|
||||
} catch (AphrontQueryException $ex) {
|
||||
// Ignore anything that goes wrong here.
|
||||
}
|
||||
}
|
||||
|
||||
public function getPID() {
|
||||
return $this->pid;
|
||||
}
|
||||
|
||||
public function getName() {
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
public function getArgv() {
|
||||
return $this->argv;
|
||||
}
|
||||
|
||||
public function getEpochStarted() {
|
||||
return $this->start;
|
||||
}
|
||||
|
||||
public function getPIDFile() {
|
||||
return $this->pidFile;
|
||||
}
|
||||
|
||||
public function getDaemonLog() {
|
||||
return $this->daemonLog;
|
||||
}
|
||||
|
||||
public function isRunning() {
|
||||
return self::isProcessRunning($this->getPID());
|
||||
}
|
||||
|
||||
public static function isProcessRunning($pid) {
|
||||
if (!$pid) {
|
||||
return false;
|
||||
|
@ -148,15 +30,4 @@ final class PhabricatorDaemonReference extends Phobject {
|
|||
return $is_running;
|
||||
}
|
||||
|
||||
public function waitForExit($seconds) {
|
||||
$start = time();
|
||||
while (time() < $start + $seconds) {
|
||||
usleep(100000);
|
||||
if (!$this->isRunning()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return !$this->isRunning();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -104,7 +104,11 @@ JX.install('Workflow', {
|
|||
var link = event.getNode('tag:a');
|
||||
|
||||
// If the link is an anchor, or does not go anywhere, ignore the event.
|
||||
var href = '' + link.getAttribute('href');
|
||||
var href = link.getAttribute('href');
|
||||
if (typeof href !== 'string') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!href.length || href[0] === '#') {
|
||||
return;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue