@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
3final class PhabricatorSearchWorker extends PhabricatorWorker {
4
5 public static function queueDocumentForIndexing(
6 $phid,
7 $parameters = null,
8 $is_strict = false) {
9
10 if ($parameters === null) {
11 $parameters = array();
12 }
13
14 parent::scheduleTask(
15 self::class,
16 array(
17 'documentPHID' => $phid,
18 'parameters' => $parameters,
19 'strict' => $is_strict,
20 ),
21 array(
22 'priority' => parent::PRIORITY_INDEX,
23 'objectPHID' => $phid,
24 ));
25 }
26
27 protected function doWork() {
28 $data = $this->getTaskData();
29 $object_phid = idx($data, 'documentPHID');
30
31 // See T12425. By the time we run an indexing task, the object it indexes
32 // may have been deleted. This is unusual, but not concerning, and failing
33 // to index these objects is correct.
34
35 // To avoid showing these non-actionable errors to users, don't report
36 // indexing exceptions unless we're in "strict" mode. This mode is set by
37 // the "bin/search index" tool.
38
39 $is_strict = idx($data, 'strict', false);
40
41 try {
42 $object = $this->loadObjectForIndexing($object_phid);
43 } catch (PhabricatorWorkerPermanentFailureException $ex) {
44 if ($is_strict) {
45 throw $ex;
46 } else {
47 return;
48 }
49 }
50
51 $engine = id(new PhabricatorIndexEngine())
52 ->setObject($object);
53
54 $parameters = idx($data, 'parameters', array());
55 $engine->setParameters($parameters);
56
57 if (!$engine->shouldIndexObject()) {
58 return;
59 }
60
61 $lock = PhabricatorGlobalLock::newLock(
62 'index',
63 array(
64 'objectPHID' => $object_phid,
65 ));
66
67 try {
68 $lock->lock(1);
69 } catch (PhutilLockException $ex) {
70 // If we fail to acquire the lock, just yield. It's expected that we may
71 // contend on this lock occasionally if a large object receives many
72 // updates in a short period of time, and it's appropriate to just retry
73 // rebuilding the index later.
74 throw new PhabricatorWorkerYieldException(15);
75 }
76
77 $caught = null;
78 try {
79 // Reload the object now that we have a lock, to make sure we have the
80 // most current version.
81 $object = $this->loadObjectForIndexing($object->getPHID());
82
83 $engine->setObject($object);
84 $engine->indexObject();
85 } catch (Exception $ex) {
86 $caught = $ex;
87 }
88
89 // Release the lock before we deal with the exception.
90 $lock->unlock();
91
92 if ($caught) {
93 if (!($caught instanceof PhabricatorWorkerPermanentFailureException)) {
94 $caught = new PhabricatorWorkerPermanentFailureException(
95 pht(
96 'Failed to update search index for document "%s": %s',
97 $object_phid,
98 $caught->getMessage()));
99 }
100
101 if ($is_strict) {
102 throw $caught;
103 }
104 }
105 }
106
107 private function loadObjectForIndexing($phid) {
108 $viewer = PhabricatorUser::getOmnipotentUser();
109
110 $object = id(new PhabricatorObjectQuery())
111 ->setViewer($viewer)
112 ->withPHIDs(array($phid))
113 ->executeOne();
114
115 if (!$object) {
116 throw new PhabricatorWorkerPermanentFailureException(
117 pht(
118 'Unable to load object "%s" to rebuild indexes.',
119 $phid));
120 }
121
122 return $object;
123 }
124
125}