@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
at upstream/main 198 lines 5.2 kB view raw
1<?php 2 3/** 4 * @extends PhabricatorCursorPagedPolicyAwareQuery<PhabricatorDaemonLog> 5 */ 6final class PhabricatorDaemonLogQuery 7 extends PhabricatorCursorPagedPolicyAwareQuery { 8 9 const STATUS_ALL = 'status-all'; 10 const STATUS_ALIVE = 'status-alive'; 11 const STATUS_RUNNING = 'status-running'; 12 13 private $ids; 14 private $notIDs; 15 private $status = self::STATUS_ALL; 16 private $daemonClasses; 17 private $allowStatusWrites; 18 private $daemonIDs; 19 20 public static function getTimeUntilUnknown() { 21 return 3 * PhutilDaemonHandle::getHeartbeatEventFrequency(); 22 } 23 24 public static function getTimeUntilDead() { 25 return 30 * PhutilDaemonHandle::getHeartbeatEventFrequency(); 26 } 27 28 public function withIDs(array $ids) { 29 $this->ids = $ids; 30 return $this; 31 } 32 33 public function withoutIDs(array $ids) { 34 $this->notIDs = $ids; 35 return $this; 36 } 37 38 public function withStatus($status) { 39 $this->status = $status; 40 return $this; 41 } 42 43 public function withDaemonClasses(array $classes) { 44 $this->daemonClasses = $classes; 45 return $this; 46 } 47 48 public function setAllowStatusWrites($allow) { 49 $this->allowStatusWrites = $allow; 50 return $this; 51 } 52 53 public function withDaemonIDs(array $daemon_ids) { 54 $this->daemonIDs = $daemon_ids; 55 return $this; 56 } 57 58 protected function loadPage() { 59 $table = new PhabricatorDaemonLog(); 60 $conn_r = $table->establishConnection('r'); 61 62 $data = queryfx_all( 63 $conn_r, 64 'SELECT * FROM %T %Q %Q %Q', 65 $table->getTableName(), 66 $this->buildWhereClause($conn_r), 67 $this->buildOrderClause($conn_r), 68 $this->buildLimitClause($conn_r)); 69 70 return $table->loadAllFromArray($data); 71 } 72 73 protected function willFilterPage(array $daemons) { 74 $unknown_delay = self::getTimeUntilUnknown(); 75 $dead_delay = self::getTimeUntilDead(); 76 77 $status_running = PhabricatorDaemonLog::STATUS_RUNNING; 78 $status_unknown = PhabricatorDaemonLog::STATUS_UNKNOWN; 79 $status_wait = PhabricatorDaemonLog::STATUS_WAIT; 80 $status_exiting = PhabricatorDaemonLog::STATUS_EXITING; 81 $status_exited = PhabricatorDaemonLog::STATUS_EXITED; 82 $status_dead = PhabricatorDaemonLog::STATUS_DEAD; 83 84 $filter = array_fuse($this->getStatusConstants()); 85 86 foreach ($daemons as $key => $daemon) { 87 $status = $daemon->getStatus(); 88 $seen = $daemon->getDateModified(); 89 90 $is_running = ($status == $status_running) || 91 ($status == $status_wait) || 92 ($status == $status_exiting); 93 94 // If we haven't seen the daemon recently, downgrade its status to 95 // unknown. 96 $unknown_time = ($seen + $unknown_delay); 97 if ($is_running && ($unknown_time < time())) { 98 $status = $status_unknown; 99 } 100 101 // If the daemon hasn't been seen in quite a while, assume it is dead. 102 $dead_time = ($seen + $dead_delay); 103 if (($status == $status_unknown) && ($dead_time < time())) { 104 $status = $status_dead; 105 } 106 107 // If we changed the daemon's status, adjust it. 108 if ($status != $daemon->getStatus()) { 109 $daemon->setStatus($status); 110 111 // ...and write it, if we're in a context where that's reasonable. 112 if ($this->allowStatusWrites) { 113 $guard = AphrontWriteGuard::beginScopedUnguardedWrites(); 114 $daemon->save(); 115 unset($guard); 116 } 117 } 118 119 // If the daemon no longer matches the filter, get rid of it. 120 if ($filter) { 121 if (empty($filter[$daemon->getStatus()])) { 122 unset($daemons[$key]); 123 } 124 } 125 } 126 127 return $daemons; 128 } 129 130 protected function buildWhereClause(AphrontDatabaseConnection $conn) { 131 $where = array(); 132 133 if ($this->ids !== null) { 134 $where[] = qsprintf( 135 $conn, 136 'id IN (%Ld)', 137 $this->ids); 138 } 139 140 if ($this->notIDs !== null) { 141 $where[] = qsprintf( 142 $conn, 143 'id NOT IN (%Ld)', 144 $this->notIDs); 145 } 146 147 if ($this->getStatusConstants()) { 148 $where[] = qsprintf( 149 $conn, 150 'status IN (%Ls)', 151 $this->getStatusConstants()); 152 } 153 154 if ($this->daemonClasses !== null) { 155 $where[] = qsprintf( 156 $conn, 157 'daemon IN (%Ls)', 158 $this->daemonClasses); 159 } 160 161 if ($this->daemonIDs !== null) { 162 $where[] = qsprintf( 163 $conn, 164 'daemonID IN (%Ls)', 165 $this->daemonIDs); 166 } 167 168 $where[] = $this->buildPagingClause($conn); 169 170 return $this->formatWhereClause($conn, $where); 171 } 172 173 private function getStatusConstants() { 174 $status = $this->status; 175 switch ($status) { 176 case self::STATUS_ALL: 177 return array(); 178 case self::STATUS_RUNNING: 179 return array( 180 PhabricatorDaemonLog::STATUS_RUNNING, 181 ); 182 case self::STATUS_ALIVE: 183 return array( 184 PhabricatorDaemonLog::STATUS_UNKNOWN, 185 PhabricatorDaemonLog::STATUS_RUNNING, 186 PhabricatorDaemonLog::STATUS_WAIT, 187 PhabricatorDaemonLog::STATUS_EXITING, 188 ); 189 default: 190 throw new Exception(pht('Unknown status "%s"!', $status)); 191 } 192 } 193 194 public function getQueryApplicationClass() { 195 return PhabricatorDaemonsApplication::class; 196 } 197 198}