@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

Use a real Query class to load daemon information

Summary:
Ref T3557. This stuff does a bunch of nonsense in the View right now. Instead, do it in a real Query class.

Fixes a long-standing bug which prevented "all daemons" from showing more than 3 days' worth of data.

Test Plan: Viewed `/daemon/`, viewed "All Daemons".

Reviewers: btrahan

Reviewed By: btrahan

CC: aran

Maniphest Tasks: T3557

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

+173 -84
+9 -4
src/__phutil_library_map__.php
··· 1019 1019 'PhabricatorDaemonCombinedLogController' => 'applications/daemon/controller/PhabricatorDaemonCombinedLogController.php', 1020 1020 'PhabricatorDaemonConsoleController' => 'applications/daemon/controller/PhabricatorDaemonConsoleController.php', 1021 1021 'PhabricatorDaemonController' => 'applications/daemon/controller/PhabricatorDaemonController.php', 1022 - 'PhabricatorDaemonDAO' => 'infrastructure/daemon/storage/PhabricatorDaemonDAO.php', 1022 + 'PhabricatorDaemonDAO' => 'applications/daemon/storage/PhabricatorDaemonDAO.php', 1023 1023 'PhabricatorDaemonEventListener' => 'applications/daemon/event/PhabricatorDaemonEventListener.php', 1024 - 'PhabricatorDaemonLog' => 'infrastructure/daemon/storage/PhabricatorDaemonLog.php', 1025 - 'PhabricatorDaemonLogEvent' => 'infrastructure/daemon/storage/PhabricatorDaemonLogEvent.php', 1024 + 'PhabricatorDaemonLog' => 'applications/daemon/storage/PhabricatorDaemonLog.php', 1025 + 'PhabricatorDaemonLogEvent' => 'applications/daemon/storage/PhabricatorDaemonLogEvent.php', 1026 1026 'PhabricatorDaemonLogEventsView' => 'applications/daemon/view/PhabricatorDaemonLogEventsView.php', 1027 1027 'PhabricatorDaemonLogListController' => 'applications/daemon/controller/PhabricatorDaemonLogListController.php', 1028 1028 'PhabricatorDaemonLogListView' => 'applications/daemon/view/PhabricatorDaemonLogListView.php', ··· 3023 3023 'PhabricatorDaemonController' => 'PhabricatorController', 3024 3024 'PhabricatorDaemonDAO' => 'PhabricatorLiskDAO', 3025 3025 'PhabricatorDaemonEventListener' => 'PhutilEventListener', 3026 - 'PhabricatorDaemonLog' => 'PhabricatorDaemonDAO', 3026 + 'PhabricatorDaemonLog' => 3027 + array( 3028 + 0 => 'PhabricatorDaemonDAO', 3029 + 1 => 'PhabricatorPolicyInterface', 3030 + ), 3027 3031 'PhabricatorDaemonLogEvent' => 'PhabricatorDaemonDAO', 3028 3032 'PhabricatorDaemonLogEventsView' => 'AphrontView', 3029 3033 'PhabricatorDaemonLogListController' => 'PhabricatorDaemonController', 3030 3034 'PhabricatorDaemonLogListView' => 'AphrontView', 3035 + 'PhabricatorDaemonLogQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 3031 3036 'PhabricatorDaemonLogViewController' => 'PhabricatorDaemonController', 3032 3037 'PhabricatorDaemonManagementDebugWorkflow' => 'PhabricatorDaemonManagementWorkflow', 3033 3038 'PhabricatorDaemonManagementLaunchWorkflow' => 'PhabricatorDaemonManagementWorkflow',
+5 -5
src/applications/daemon/controller/PhabricatorDaemonConsoleController.php
··· 57 57 $completed_panel->appendChild($completed_table); 58 58 $completed_panel->setNoBackground(); 59 59 60 - $logs = id(new PhabricatorDaemonLog())->loadAllWhere( 61 - '`status` = %s ORDER BY id DESC', 62 - 'run'); 63 - 60 + $logs = id(new PhabricatorDaemonLogQuery()) 61 + ->setViewer($user) 62 + ->withStatus(PhabricatorDaemonLogQuery::STATUS_ALIVE) 63 + ->execute(); 64 64 65 65 $daemon_header = id(new PhabricatorHeaderView()) 66 - ->setHeader(pht('Recent Daemons')); 66 + ->setHeader(pht('Active Daemons')); 67 67 68 68 $daemon_table = new PhabricatorDaemonLogListView(); 69 69 $daemon_table->setUser($user);
+7 -12
src/applications/daemon/controller/PhabricatorDaemonLogListController.php
··· 5 5 6 6 public function processRequest() { 7 7 $request = $this->getRequest(); 8 + $viewer = $request->getUser(); 8 9 9 - $pager = new AphrontPagerView(); 10 - $pager->setOffset($request->getInt('page')); 11 - 12 - $clause = '1 = 1'; 13 - 14 - $logs = id(new PhabricatorDaemonLog())->loadAllWhere( 15 - '%Q ORDER BY id DESC LIMIT %d, %d', 16 - $clause, 17 - $pager->getOffset(), 18 - $pager->getPageSize() + 1); 10 + $pager = new AphrontCursorPagerView(); 11 + $pager->readFromRequest($request); 19 12 20 - $logs = $pager->sliceResults($logs); 21 - $pager->setURI($request->getRequestURI(), 'page'); 13 + $logs = id(new PhabricatorDaemonLogQuery()) 14 + ->setViewer($viewer) 15 + ->executeWithCursorPager($pager); 22 16 23 17 $daemon_table = new PhabricatorDaemonLogListView(); 24 18 $daemon_table->setUser($request->getUser()); ··· 33 27 $nav->selectFilter('log'); 34 28 $nav->setCrumbs($crumbs); 35 29 $nav->appendChild($daemon_table); 30 + $nav->appendChild($pager); 36 31 37 32 return $this->buildApplicationPage( 38 33 $nav,
+107 -1
src/applications/daemon/query/PhabricatorDaemonLogQuery.php
··· 1 1 <?php 2 2 3 - final class PhabricatorDaemonLogQuery { 3 + final class PhabricatorDaemonLogQuery 4 + extends PhabricatorCursorPagedPolicyAwareQuery { 5 + 6 + const STATUS_ALL = 'status-all'; 7 + const STATUS_ALIVE = 'status-alive'; 8 + 9 + private $status = self::STATUS_ALL; 4 10 5 11 public static function getTimeUntilUnknown() { 6 12 return 3 * PhutilDaemonOverseer::HEARTBEAT_WAIT; ··· 8 14 9 15 public static function getTimeUntilDead() { 10 16 return 30 * PhutilDaemonOverseer::HEARTBEAT_WAIT; 17 + } 18 + 19 + public function withStatus($status) { 20 + $this->status = $status; 21 + return $this; 22 + } 23 + 24 + public function loadPage() { 25 + $table = new PhabricatorDaemonLog(); 26 + $conn_r = $table->establishConnection('r'); 27 + 28 + $data = queryfx_all( 29 + $conn_r, 30 + 'SELECT * FROM %T %Q %Q %Q', 31 + $table->getTableName(), 32 + $this->buildWhereClause($conn_r), 33 + $this->buildOrderClause($conn_r), 34 + $this->buildLimitClause($conn_r)); 35 + 36 + return $table->loadAllFromArray($data); 37 + } 38 + 39 + public function willFilterPage(array $daemons) { 40 + $unknown_delay = PhabricatorDaemonLogQuery::getTimeUntilUnknown(); 41 + $dead_delay = PhabricatorDaemonLogQuery::getTimeUntilDead(); 42 + 43 + $status_running = PhabricatorDaemonLog::STATUS_RUNNING; 44 + $status_unknown = PhabricatorDaemonLog::STATUS_UNKNOWN; 45 + $status_wait = PhabricatorDaemonLog::STATUS_WAIT; 46 + $status_exited = PhabricatorDaemonLog::STATUS_EXITED; 47 + $status_dead = PhabricatorDaemonLog::STATUS_DEAD; 48 + 49 + $filter = array_fuse($this->getStatusConstants()); 50 + 51 + foreach ($daemons as $key => $daemon) { 52 + $status = $daemon->getStatus(); 53 + $seen = $daemon->getDateModified(); 54 + 55 + $is_running = ($status == $status_running) || 56 + ($status == $status_wait); 57 + 58 + // If we haven't seen the daemon recently, downgrade its status to 59 + // unknown. 60 + $unknown_time = ($seen + $unknown_delay); 61 + if ($is_running && ($unknown_time < time())) { 62 + $status = $status_unknown; 63 + } 64 + 65 + // If the daemon hasn't been seen in quite a while, assume it is dead. 66 + $dead_time = ($seen + $dead_delay); 67 + if (($status == $status_unknown) && ($dead_time < time())) { 68 + $status = $status_dead; 69 + } 70 + 71 + // If we changed the daemon's status, update it. 72 + if ($status != $daemon->getStatus()) { 73 + $guard = AphrontWriteGuard::beginScopedUnguardedWrites(); 74 + $daemon->setStatus($status)->save(); 75 + unset($guard); 76 + } 77 + 78 + // If the daemon no longer matches the filter, get rid of it. 79 + if ($filter) { 80 + if (empty($filter[$daemon->getStatus()])) { 81 + unset($daemons[$key]); 82 + } 83 + } 84 + } 85 + 86 + return $daemons; 87 + } 88 + 89 + private function buildWhereClause(AphrontDatabaseConnection $conn_r) { 90 + $where = array(); 91 + 92 + if ($this->getStatusConstants()) { 93 + $where[] = qsprintf( 94 + $conn_r, 95 + 'status IN (%Ls)', 96 + $this->getStatusConstants()); 97 + } 98 + 99 + $where[] = $this->buildPagingClause($conn_r); 100 + return $this->formatWhereClause($where); 101 + } 102 + 103 + private function getStatusConstants() { 104 + $status = $this->status; 105 + switch ($status) { 106 + case self::STATUS_ALL: 107 + return array(); 108 + case self::STATUS_ALIVE: 109 + return array( 110 + PhabricatorDaemonLog::STATUS_UNKNOWN, 111 + PhabricatorDaemonLog::STATUS_RUNNING, 112 + PhabricatorDaemonLog::STATUS_WAIT, 113 + ); 114 + default: 115 + throw new Exception("Unknown status '{$status}'!"); 116 + } 11 117 } 12 118 13 119 }
+44
src/applications/daemon/storage/PhabricatorDaemonLog.php
··· 1 + <?php 2 + 3 + final class PhabricatorDaemonLog extends PhabricatorDaemonDAO 4 + implements PhabricatorPolicyInterface { 5 + 6 + const STATUS_UNKNOWN = 'unknown'; 7 + const STATUS_RUNNING = 'run'; 8 + const STATUS_DEAD = 'dead'; 9 + const STATUS_WAIT = 'wait'; 10 + const STATUS_EXITED = 'exit'; 11 + 12 + protected $daemon; 13 + protected $host; 14 + protected $pid; 15 + protected $argv; 16 + protected $status; 17 + 18 + public function getConfiguration() { 19 + return array( 20 + self::CONFIG_SERIALIZATION => array( 21 + 'argv' => self::SERIALIZATION_JSON, 22 + ), 23 + ) + parent::getConfiguration(); 24 + } 25 + 26 + 27 + /* -( PhabricatorPolicyInterface )----------------------------------------- */ 28 + 29 + 30 + public function getCapabilities() { 31 + return array( 32 + PhabricatorPolicyCapability::CAN_VIEW, 33 + ); 34 + } 35 + 36 + public function getPolicy($capability) { 37 + return PhabricatorPolicies::POLICY_ADMIN; 38 + } 39 + 40 + public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { 41 + return false; 42 + } 43 + 44 + }
+1 -37
src/applications/daemon/view/PhabricatorDaemonLogListView.php
··· 19 19 20 20 $list = id(new PhabricatorObjectItemListView()); 21 21 foreach ($this->daemonLogs as $log) { 22 - 23 - // TODO: VVV Move this stuff to a Query class. VVV 24 - 25 - $expect_heartbeat = PhabricatorDaemonLogQuery::getTimeUntilUnknown(); 26 - $assume_dead = PhabricatorDaemonLogQuery::getTimeUntilDead(); 27 - 28 - $status_running = PhabricatorDaemonLog::STATUS_RUNNING; 29 - $status_unknown = PhabricatorDaemonLog::STATUS_UNKNOWN; 30 - $status_wait = PhabricatorDaemonLog::STATUS_WAIT; 31 - $status_exited = PhabricatorDaemonLog::STATUS_EXITED; 32 - $status_dead = PhabricatorDaemonLog::STATUS_DEAD; 33 - 34 - $status = $log->getStatus(); 35 - $heartbeat_timeout = $log->getDateModified() + $expect_heartbeat; 36 - if ($status == $status_running && $heartbeat_timeout < time()) { 37 - $status = $status_unknown; 38 - } 39 - 40 - if ($status == $status_unknown && $assume_dead < time()) { 41 - $guard = AphrontWriteGuard::beginScopedUnguardedWrites(); 42 - $log->setStatus($status_dead)->save(); 43 - unset($guard); 44 - } 45 - 46 - if ($status != $status_running && 47 - $log->getDateModified() + (3 * 86400) < time()) { 48 - // Don't show rows that haven't been running for more than 49 - // three days. We should probably prune these out of the 50 - // DB similar to the code above, but we don't need to be 51 - // conservative and do it only on the same host 52 - 53 - // TODO: This should not apply to the "all daemons" view! 54 - continue; 55 - } 56 - 57 - // TODO: ^^^^ ALL THAT STUFF ^^^ 58 - 59 22 $id = $log->getID(); 60 23 $epoch = $log->getDateCreated(); 61 24 ··· 65 28 ->setHref("/daemon/log/{$id}/") 66 29 ->addIcon('none', phabricator_datetime($epoch, $this->user)); 67 30 31 + $status = $log->getStatus(); 68 32 switch ($status) { 69 33 case PhabricatorDaemonLog::STATUS_RUNNING: 70 34 $item->setBarColor('green');
src/infrastructure/daemon/storage/PhabricatorDaemonDAO.php src/applications/daemon/storage/PhabricatorDaemonDAO.php
-25
src/infrastructure/daemon/storage/PhabricatorDaemonLog.php
··· 1 - <?php 2 - 3 - final class PhabricatorDaemonLog extends PhabricatorDaemonDAO { 4 - 5 - const STATUS_UNKNOWN = 'unknown'; 6 - const STATUS_RUNNING = 'run'; 7 - const STATUS_DEAD = 'dead'; 8 - const STATUS_WAIT = 'wait'; 9 - const STATUS_EXITED = 'exit'; 10 - 11 - protected $daemon; 12 - protected $host; 13 - protected $pid; 14 - protected $argv; 15 - protected $status; 16 - 17 - public function getConfiguration() { 18 - return array( 19 - self::CONFIG_SERIALIZATION => array( 20 - 'argv' => self::SERIALIZATION_JSON, 21 - ), 22 - ) + parent::getConfiguration(); 23 - } 24 - 25 - }
src/infrastructure/daemon/storage/PhabricatorDaemonLogEvent.php src/applications/daemon/storage/PhabricatorDaemonLogEvent.php