Changeset View
Changeset View
Standalone View
Standalone View
src/infrastructure/daemon/control/PhabricatorDaemonReference.php
<?php | <?php | ||||
final class PhabricatorDaemonReference extends Phobject { | // TODO: See T13321. After the removal of daemon PID files this class | ||||
// no longer makes as much sense as it once did. | |||||
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) { | final class PhabricatorDaemonReference extends Phobject { | ||||
$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) { | public static function isProcessRunning($pid) { | ||||
if (!$pid) { | if (!$pid) { | ||||
return false; | return false; | ||||
} | } | ||||
if (function_exists('posix_kill')) { | if (function_exists('posix_kill')) { | ||||
// This may fail if we can't signal the process because we are running as | // This may fail if we can't signal the process because we are running as | ||||
Show All 10 Lines | if (function_exists('posix_kill')) { | ||||
// If we don't have the posix extension, just exec. | // If we don't have the posix extension, just exec. | ||||
list($err) = exec_manual('ps %s', $pid); | list($err) = exec_manual('ps %s', $pid); | ||||
$is_running = ($err == 0); | $is_running = ($err == 0); | ||||
} | } | ||||
return $is_running; | return $is_running; | ||||
} | } | ||||
public function waitForExit($seconds) { | |||||
$start = time(); | |||||
while (time() < $start + $seconds) { | |||||
usleep(100000); | |||||
if (!$this->isRunning()) { | |||||
return true; | |||||
} | |||||
} | |||||
return !$this->isRunning(); | |||||
} | |||||
} | } |