@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Drive "phd stop" entirely from the process list, not PID files on disk

Summary:
Ref T13321. Depends on D20600. Make `bin/phd stop` mean:

- `bin/phd stop`: Stop all processes which have daemon process titles. If we're instanced, only stop daemons for the current instance.
- `bin/phd stop --force`: Stop all processes which have deamon process titles for any instance.

We no longer read or care about PID files on disk, and this moves us away from PID files.

This makes unusual flag `--gently` do nothing. A followup will update the documentation and flags to reflect actual usage/behavior.

This also removes the ability to stop specific PIDs. This was somewhat useful long, long ago when you might explicitly run different copies of the `PullLocal` daemon with flags to control which repositories they updated, but with the advent of clustering it's no longer valid to run custom daemon loadouts.

Test Plan: Ran `bin/phd start`, then `bin/phd stop`. Saw instance daemons stop. Ran `bin/phd stop --force`, saw all daemons stop.

Reviewers: amckinley

Reviewed By: amckinley

Maniphest Tasks: T13321

Differential Revision: https://secure.phabricator.com/D20601

+61 -91
-1
src/applications/daemon/management/PhabricatorDaemonManagementRestartWorkflow.php
··· 35 35 36 36 public function execute(PhutilArgumentParser $args) { 37 37 $err = $this->executeStopCommand( 38 - array(), 39 38 array( 40 39 'graceful' => $args->getArg('graceful'), 41 40 'force' => $args->getArg('force'),
-1
src/applications/daemon/management/PhabricatorDaemonManagementStopWorkflow.php
··· 42 42 43 43 public function execute(PhutilArgumentParser $args) { 44 44 return $this->executeStopCommand( 45 - $args->getArg('pids'), 46 45 array( 47 46 'graceful' => $args->getArg('graceful'), 48 47 'force' => $args->getArg('force'),
+61 -89
src/applications/daemon/management/PhabricatorDaemonManagementWorkflow.php
··· 386 386 return 0; 387 387 } 388 388 389 - final protected function executeStopCommand( 390 - array $pids, 391 - array $options) { 392 - 393 - $console = PhutilConsole::getConsole(); 394 - 389 + final protected function executeStopCommand(array $options) { 395 390 $grace_period = idx($options, 'graceful', 15); 396 391 $force = idx($options, 'force'); 397 - $gently = idx($options, 'gently'); 392 + 393 + $query = id(new PhutilProcessQuery()) 394 + ->withIsOverseer(true); 398 395 399 - if ($gently && $force) { 400 - throw new PhutilArgumentUsageException( 401 - pht( 402 - 'You can not specify conflicting options %s and %s together.', 403 - '--gently', 404 - '--force')); 396 + $instance = PhabricatorEnv::getEnvConfig('cluster.instance'); 397 + if ($instance !== null && !$force) { 398 + $query->withInstances(array($instance)); 405 399 } 406 400 407 - $daemons = $this->loadRunningDaemons(); 408 - if (!$daemons) { 409 - $survivors = array(); 410 - if (!$pids && !$gently) { 411 - $survivors = $this->processRogueDaemons( 412 - $grace_period, 413 - $warn = true, 414 - $force); 415 - } 416 - if (!$survivors) { 417 - $console->writeErr( 418 - "%s\n", 419 - pht('There are no running Phabricator daemons.')); 420 - } 421 - return 0; 401 + try { 402 + $process_refs = $query->execute(); 403 + } catch (Exception $ex) { 404 + // See T13321. If this fails for some reason, just continue for now so 405 + // that daemon management still works. In the long run, we don't expect 406 + // this to fail, but I don't want to break this workflow while we iron 407 + // bugs out. 408 + 409 + // See T12827. Particularly, this is likely to fail on Solaris. 410 + 411 + phlog($ex); 412 + 413 + $process_refs = array(); 422 414 } 423 415 424 - $stop_pids = $this->selectDaemonPIDs($daemons, $pids); 416 + if (!$process_refs) { 417 + if ($instance !== null && !$force) { 418 + $this->logInfo( 419 + pht('NO DAEMONS'), 420 + pht( 421 + 'There are no running daemons for the current instance ("%s"). '. 422 + 'Use "--force" to stop daemons for all instances.', 423 + $instance)); 424 + } else { 425 + $this->logInfo( 426 + pht('NO DAEMONS'), 427 + pht('There are no running daemons.')); 428 + } 425 429 426 - if (!$stop_pids) { 427 - $console->writeErr("%s\n", pht('No daemons to kill.')); 428 430 return 0; 429 431 } 430 432 431 - $survivors = $this->sendStopSignals($stop_pids, $grace_period); 433 + $process_refs = mpull($process_refs, null, 'getPID'); 432 434 433 - // Try to clean up PID files for daemons we killed. 434 - $remove = array(); 435 - foreach ($daemons as $daemon) { 436 - $pid = $daemon->getPID(); 437 - if (empty($stop_pids[$pid])) { 438 - // We did not try to stop this overseer. 439 - continue; 440 - } 435 + $stop_pids = array_keys($process_refs); 436 + $live_pids = $this->sendStopSignals($stop_pids, $grace_period); 441 437 442 - if (isset($survivors[$pid])) { 443 - // We weren't able to stop this overseer. 444 - continue; 445 - } 438 + $stop_pids = array_fuse($stop_pids); 439 + $live_pids = array_fuse($live_pids); 446 440 447 - if (!$daemon->getPIDFile()) { 448 - // We don't know where the PID file is. 449 - continue; 450 - } 441 + $dead_pids = array_diff_key($stop_pids, $live_pids); 451 442 452 - $remove[] = $daemon->getPIDFile(); 443 + foreach ($dead_pids as $dead_pid) { 444 + $dead_ref = $process_refs[$dead_pid]; 445 + $this->logOkay( 446 + pht('STOP'), 447 + pht( 448 + 'Stopped PID %d ("%s")', 449 + $dead_pid, 450 + $dead_ref->getCommand())); 453 451 } 454 452 455 - foreach (array_unique($remove) as $remove_file) { 456 - Filesystem::remove($remove_file); 453 + foreach ($live_pids as $live_pid) { 454 + $live_ref = $process_refs[$live_pid]; 455 + $this->logFail( 456 + pht('SURVIVED'), 457 + pht( 458 + 'Unable to stop PID %d ("%s").', 459 + $live_pid, 460 + $live_ref->getCommand())); 457 461 } 458 462 459 - if (!$gently) { 460 - $this->processRogueDaemons($grace_period, !$pids, $force); 463 + if ($live_pids) { 464 + $this->logWarn( 465 + pht('SURVIVORS'), 466 + pht( 467 + 'Unable to stop all daemon processes. You may need to run this '. 468 + 'command as root with "sudo".')); 461 469 } 462 470 463 471 return 0; ··· 490 498 } 491 499 492 500 return 0; 493 - } 494 - 495 - private function processRogueDaemons($grace_period, $warn, $force_stop) { 496 - $console = PhutilConsole::getConsole(); 497 - 498 - $rogue_daemons = PhutilDaemonOverseer::findRunningDaemons(); 499 - if ($rogue_daemons) { 500 - if ($force_stop) { 501 - $rogue_pids = ipull($rogue_daemons, 'pid'); 502 - $survivors = $this->sendStopSignals($rogue_pids, $grace_period); 503 - if ($survivors) { 504 - $console->writeErr( 505 - "%s\n", 506 - pht( 507 - 'Unable to stop processes running without PID files. '. 508 - 'Try running this command again with sudo.')); 509 - } 510 - } else if ($warn) { 511 - $console->writeErr("%s\n", $this->getForceStopHint($rogue_daemons)); 512 - } 513 - } 514 - 515 - return $rogue_daemons; 516 - } 517 - 518 - private function getForceStopHint($rogue_daemons) { 519 - $debug_output = ''; 520 - foreach ($rogue_daemons as $rogue) { 521 - $debug_output .= $rogue['pid'].' '.$rogue['command']."\n"; 522 - } 523 - return pht( 524 - "There are processes running that look like Phabricator daemons but ". 525 - "have no corresponding PID files:\n\n%s\n\n". 526 - "Stop these processes by re-running this command with the %s parameter.", 527 - $debug_output, 528 - '--force'); 529 501 } 530 502 531 503 private function sendStopSignals($pids, $grace_period) {