@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.

Allow archived tasks to be queried by object PHID and order by id

Summary: Ref T5402.

Test Plan:
- Queried archived tasks.
- Grepped for use sites and verified no other callsites are order-sensitive.

Reviewers: btrahan

Reviewed By: btrahan

Subscribers: epriestley

Maniphest Tasks: T5402

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

+83 -10
+5 -2
src/applications/daemon/controller/PhabricatorDaemonConsoleController.php
··· 131 131 $daemon_panel->appendChild($daemon_table); 132 132 133 133 134 - $tasks = id(new PhabricatorWorkerActiveTask())->loadAllWhere( 135 - 'leaseOwner IS NOT NULL'); 134 + $tasks = id(new PhabricatorWorkerLeaseQuery()) 135 + ->setSkipLease(true) 136 + ->withLeasedTasks(true) 137 + ->setLimit(100) 138 + ->execute(); 136 139 137 140 $tasks_table = id(new PhabricatorDaemonTasksTableView()) 138 141 ->setTasks($tasks)
+14 -2
src/infrastructure/daemon/workers/query/PhabricatorWorkerArchiveTaskQuery.php
··· 6 6 private $ids; 7 7 private $dateModifiedSince; 8 8 private $dateCreatedBefore; 9 + private $objectPHIDs; 9 10 private $limit; 10 11 11 12 public function withIDs(array $ids) { ··· 23 24 return $this; 24 25 } 25 26 27 + public function withObjectPHIDs(array $phids) { 28 + $this->objectPHIDs = $phids; 29 + return $this; 30 + } 31 + 26 32 public function setLimit($limit) { 27 33 $this->limit = $limit; 28 34 return $this; 29 35 } 30 36 31 37 public function execute() { 32 - 33 38 $task_table = new PhabricatorWorkerArchiveTask(); 34 39 35 40 $conn_r = $task_table->establishConnection('r'); 36 41 37 42 $rows = queryfx_all( 38 43 $conn_r, 39 - 'SELECT * FROM %T %Q %Q', 44 + 'SELECT * FROM %T %Q ORDER BY id DESC %Q', 40 45 $task_table->getTableName(), 41 46 $this->buildWhereClause($conn_r), 42 47 $this->buildLimitClause($conn_r)); ··· 52 57 $conn_r, 53 58 'ids in (%Ld)', 54 59 $this->ids); 60 + } 61 + 62 + if ($this->objectPHIDs !== null) { 63 + $where[] = qsprintf( 64 + $conn_r, 65 + 'objectPHID IN (%Ls)', 66 + $this->objectPHIDs); 55 67 } 56 68 57 69 if ($this->dateModifiedSince) {
+62 -6
src/infrastructure/daemon/workers/query/PhabricatorWorkerLeaseQuery.php
··· 5 5 */ 6 6 final class PhabricatorWorkerLeaseQuery extends PhabricatorQuery { 7 7 8 + const PHASE_LEASED = 'leased'; 8 9 const PHASE_UNLEASED = 'unleased'; 9 10 const PHASE_EXPIRED = 'expired'; 10 11 ··· 12 13 private $objectPHIDs; 13 14 private $limit; 14 15 private $skipLease; 16 + private $leased = false; 15 17 16 18 public static function getDefaultWaitBeforeRetry() { 17 19 return phutil_units('5 minutes in seconds'); ··· 45 47 return $this; 46 48 } 47 49 50 + /** 51 + * Select only leased tasks, only unleased tasks, or both types of task. 52 + * 53 + * By default, queries select only unleased tasks (equivalent to passing 54 + * `false` to this method). You can pass `true` to select only leased tasks, 55 + * or `null` to ignore the lease status of tasks. 56 + * 57 + * If your result set potentially includes leased tasks, you must disable 58 + * leasing using @{method:setSkipLease}. These options are intended for use 59 + * when displaying task status information. 60 + * 61 + * @param mixed `true` to select only leased tasks, `false` to select only 62 + * unleased tasks (default), or `null` to select both. 63 + * @return this 64 + */ 65 + public function withLeasedTasks($leased) { 66 + $this->leased = $leased; 67 + return $this; 68 + } 69 + 48 70 public function setLimit($limit) { 49 71 $this->limit = $limit; 50 72 return $this; ··· 52 74 53 75 public function execute() { 54 76 if (!$this->limit) { 55 - throw new Exception('You must setLimit() when leasing tasks.'); 77 + throw new Exception( 78 + pht('You must setLimit() when leasing tasks.')); 79 + } 80 + 81 + if ($this->leased !== false) { 82 + if (!$this->skipLease) { 83 + throw new Exception( 84 + pht( 85 + 'If you potentially select leased tasks using withLeasedTasks(), '. 86 + 'you MUST disable lease acquisition by calling setSkipLease().')); 87 + } 56 88 } 57 89 58 90 $task_table = new PhabricatorWorkerActiveTask(); ··· 65 97 // find enough tasks, try tasks with expired leases (i.e., tasks which have 66 98 // previously failed). 67 99 68 - $phases = array( 69 - self::PHASE_UNLEASED, 70 - self::PHASE_EXPIRED, 71 - ); 100 + // If we're selecting leased tasks, look for them first. 101 + 102 + $phases = array(); 103 + if ($this->leased !== false) { 104 + $phases[] = self::PHASE_LEASED; 105 + } 106 + if ($this->leased !== true) { 107 + $phases[] = self::PHASE_UNLEASED; 108 + $phases[] = self::PHASE_EXPIRED; 109 + } 72 110 $limit = $this->limit; 73 111 74 112 $leased = 0; ··· 160 198 $tasks[$row['id']]->setData($task_data); 161 199 } 162 200 201 + if ($this->skipLease) { 202 + // Reorder rows into the original phase order if this is a status query. 203 + $tasks = array_select_keys($tasks, $task_ids); 204 + } 205 + 163 206 return $tasks; 164 207 } 165 208 ··· 167 210 $where = array(); 168 211 169 212 switch ($phase) { 213 + case self::PHASE_LEASED: 214 + $where[] = 'leaseOwner IS NOT NULL'; 215 + $where[] = 'leaseExpires >= UNIX_TIMESTAMP()'; 216 + break; 170 217 case self::PHASE_UNLEASED: 171 218 $where[] = 'leaseOwner IS NULL'; 172 219 break; ··· 177 224 throw new Exception("Unknown phase '{$phase}'!"); 178 225 } 179 226 180 - if ($this->ids) { 227 + if ($this->ids !== null) { 181 228 $where[] = qsprintf($conn_w, 'id IN (%Ld)', $this->ids); 182 229 } 183 230 ··· 199 246 // `IN (NULL)` doesn't match NULL. 200 247 201 248 switch ($phase) { 249 + case self::PHASE_LEASED: 250 + throw new Exception( 251 + pht( 252 + 'Trying to lease tasks selected in the leased phase! This is '. 253 + 'intended to be imposssible.')); 202 254 case self::PHASE_UNLEASED: 203 255 $where[] = qsprintf($conn_w, 'leaseOwner IS NULL'); 204 256 $where[] = qsprintf($conn_w, 'id IN (%Ld)', ipull($rows, 'id')); ··· 223 275 224 276 private function buildOrderClause(AphrontDatabaseConnection $conn_w, $phase) { 225 277 switch ($phase) { 278 + case self::PHASE_LEASED: 279 + // Ideally we'd probably order these by lease acquisition time, but 280 + // we don't have that handy and this is a good approximation. 281 + return qsprintf($conn_w, 'ORDER BY priority ASC, id ASC'); 226 282 case self::PHASE_UNLEASED: 227 283 // When selecting new tasks, we want to consume them in order of 228 284 // increasing priority (and then FIFO).
+1
src/infrastructure/daemon/workers/storage/PhabricatorWorkerActiveTask.php
··· 119 119 ->setFailureCount($this->getFailureCount()) 120 120 ->setDataID($this->getDataID()) 121 121 ->setPriority($this->getPriority()) 122 + ->setObjectPHID($this->getObjectPHID()) 122 123 ->setResult($result) 123 124 ->setDuration($duration); 124 125
+1
src/infrastructure/daemon/workers/storage/PhabricatorWorkerArchiveTask.php
··· 84 84 ->setFailureCount(0) 85 85 ->setDataID($this->getDataID()) 86 86 ->setPriority($this->getPriority()) 87 + ->setObjectPHID($this->getObjectPHID()) 87 88 ->insert(); 88 89 89 90 $this->setDataID(null);