From e0eb6dd6b21c129c775d8bb2bec203ae0d756d0f Mon Sep 17 00:00:00 2001 From: Yuriy Andamasov Date: Fri, 22 May 2026 11:48:30 +0300 Subject: Engine: Add reindexAbstractDocument() + executeRequest() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit reindexAbstractDocument builds the document body with documentType as a real field (replacing the bundled engine's per-type URL segment), then PUTs to the typeless /_doc/{phid} URL via the new helper. executeRequest mirrors the bundled engine's HTTPSFuture pattern; it's private and not test-targeted directly (smoke tests in V1-V3 exercise the full wire path). 🤖 Generated by [robots](https://vyos.io) --- .../VyOSElasticModernFulltextStorageEngine.php | 104 ++++++++++++++++++++- 1 file changed, 101 insertions(+), 3 deletions(-) (limited to 'src/engine/VyOSElasticModernFulltextStorageEngine.php') diff --git a/src/engine/VyOSElasticModernFulltextStorageEngine.php b/src/engine/VyOSElasticModernFulltextStorageEngine.php index 42e2fd6..211a196 100644 --- a/src/engine/VyOSElasticModernFulltextStorageEngine.php +++ b/src/engine/VyOSElasticModernFulltextStorageEngine.php @@ -9,6 +9,7 @@ abstract class VyOSElasticModernFulltextStorageEngine private $version = null; private $index; + private $timeout = 15; public function setService(PhabricatorSearchService $service) { $this->service = $service; // inherited protected property @@ -173,11 +174,108 @@ abstract class VyOSElasticModernFulltextStorageEngine return new VyOSElasticModernHost($this); } + public function setTimeout($timeout) { + $this->timeout = $timeout; + return $this; + } + + public function getTimeout() { + return $this->timeout; + } + public function reindexAbstractDocument( PhabricatorSearchAbstractDocument $doc) { - throw new Exception(pht( - 'reindexAbstractDocument() is not yet implemented on '. - 'VyOSElasticModernFulltextStorageEngine; lands in Task E7.')); + + $host = $this->getHostForWrite(); + + $type = $doc->getDocumentType(); + $phid = $doc->getPHID(); + + // The handle query mirrors the bundled engine's pattern; it + // populates the handle cache so subsequent field-data lookups + // don't issue redundant queries. + $handle = id(new PhabricatorHandleQuery()) + ->setViewer(PhabricatorUser::getOmnipotentUser()) + ->withPHIDs(array($phid)) + ->executeOne(); + + $spec = array( + 'title' => $doc->getDocumentTitle(), + 'dateCreated' => $doc->getDocumentCreated(), + 'lastModified' => $doc->getDocumentModified(), + 'documentType' => $type, + ); + + foreach ($doc->getFieldData() as $field) { + list($field_name, $corpus, $aux) = $field; + if (!isset($spec[$field_name])) { + $spec[$field_name] = array($corpus); + } else { + $spec[$field_name][] = $corpus; + } + if ($aux !== null) { + $spec[$field_name][] = $aux; + } + } + + foreach ($doc->getRelationshipData() as $field) { + list($field_name, $related_phid, $rtype, $time) = $field; + if (!isset($spec[$field_name])) { + $spec[$field_name] = array($related_phid); + } else { + $spec[$field_name][] = $related_phid; + } + if ($time) { + $spec[$field_name.'_ts'] = $time; + } + } + + $this->executeRequest( + $host, + $this->getDocumentUri($type, $phid), + $spec, + 'PUT'); + } + + private function executeRequest( + VyOSElasticModernHost $host, $path, array $data, $method = 'GET') { + + $uri = $host->getURI($path); + $data = phutil_json_encode($data); + $future = new HTTPSFuture($uri, $data); + $future->addHeader('Content-Type', 'application/json'); + + if ($method !== 'GET') { + $future->setMethod($method); + } + if ($this->getTimeout()) { + $future->setTimeout($this->getTimeout()); + } + + try { + list($body) = $future->resolvex(); + } catch (HTTPFutureResponseStatus $ex) { + if ($ex->isTimeout() || (int)$ex->getStatusCode() > 499) { + $host->didHealthCheck(false); + } + throw $ex; + } + + if ($method !== 'GET') { + return null; + } + + try { + $decoded = phutil_json_decode($body); + $host->didHealthCheck(true); + return $decoded; + } catch (PhutilJSONParserException $ex) { + $host->didHealthCheck(false); + throw new Exception( + pht('Elasticsearch server returned invalid JSON.'), + 0, + $ex); + } } public function executeSearch(PhabricatorSavedQuery $query) { -- cgit v1.2.3 From 3a4580e35a0c7a6480aeee9ec4acf90d0fa85326 Mon Sep 17 00:00:00 2001 From: Yuriy Andamasov Date: Sat, 23 May 2026 13:47:45 +0300 Subject: E7 fixup: move didHealthCheck(true) to HTTP-success boundary in executeRequest() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously the success health-check was called inside the JSON-decode try block. This was wrong: a valid HTTP 200 response with non-JSON body (e.g. ES maintenance page) would mark the host as *unhealthy* because JSON parse failure triggered didHealthCheck(false). The host is demonstrably reachable and responding; only the application layer failed. Move didHealthCheck(true) to immediately after list($body) = resolvex() succeeds, before the GET/non-GET branch. Remove the now-unnecessary didHealthCheck(false) from the JSON catch block — only network/timeout failures belong in the health-check false path. 🤖 Generated by [robots](https://vyos.io) --- src/engine/VyOSElasticModernFulltextStorageEngine.php | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'src/engine/VyOSElasticModernFulltextStorageEngine.php') diff --git a/src/engine/VyOSElasticModernFulltextStorageEngine.php b/src/engine/VyOSElasticModernFulltextStorageEngine.php index 211a196..e036082 100644 --- a/src/engine/VyOSElasticModernFulltextStorageEngine.php +++ b/src/engine/VyOSElasticModernFulltextStorageEngine.php @@ -261,16 +261,18 @@ abstract class VyOSElasticModernFulltextStorageEngine throw $ex; } + // HTTP request succeeded — mark the host as healthy regardless of whether + // the response body is valid JSON. JSON parse failure is an application + // error, not a host-connectivity failure. + $host->didHealthCheck(true); + if ($method !== 'GET') { return null; } try { - $decoded = phutil_json_decode($body); - $host->didHealthCheck(true); - return $decoded; + return phutil_json_decode($body); } catch (PhutilJSONParserException $ex) { - $host->didHealthCheck(false); throw new Exception( pht('Elasticsearch server returned invalid JSON.'), 0, -- cgit v1.2.3