@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<?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}