Skip to content

Commit 8fb8b90

Browse files
committed
feat: added API for healthchecks for Elasticsearch and OpenSearch
1 parent b2e2e84 commit 8fb8b90

File tree

5 files changed

+102
-8
lines changed

5 files changed

+102
-8
lines changed

phpmyfaq/src/phpMyFAQ/Controller/Administration/Api/ElasticsearchController.php

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
use phpMyFAQ\Controller\AbstractController;
2525
use phpMyFAQ\Core\Exception;
2626
use phpMyFAQ\Enums\PermissionType;
27+
use phpMyFAQ\Faq;
2728
use phpMyFAQ\Instance\Elasticsearch;
2829
use phpMyFAQ\Translation;
2930
use Symfony\Component\HttpFoundation\JsonResponse;
@@ -32,12 +33,16 @@
3233

3334
final class ElasticsearchController extends AbstractController
3435
{
36+
/**
37+
* @throws \Exception
38+
*/
3539
#[Route(path: './admin/api/elasticsearch/create', name: 'admin.api.elasticsearch.create', methods: ['POST'])]
3640
public function create(): JsonResponse
3741
{
3842
$this->userHasPermission(PermissionType::CONFIGURATION_EDIT);
3943

40-
$elasticsearch = new Elasticsearch($this->configuration);
44+
/** @var Elasticsearch $elasticsearch */
45+
$elasticsearch = $this->container->get(id: 'phpmyfaq.instance.elasticsearch');
4146

4247
try {
4348
$elasticsearch->createIndex();
@@ -50,14 +55,15 @@ public function create(): JsonResponse
5055
}
5156

5257
/**
53-
* @throws Exception
58+
* @throws \Exception
5459
*/
5560
#[Route(path: './admin/api/elasticsearch/drop', name: 'admin.api.elasticsearch.drop', methods: ['DELETE'])]
5661
public function drop(): JsonResponse
5762
{
5863
$this->userHasPermission(PermissionType::CONFIGURATION_EDIT);
5964

60-
$elasticsearch = new Elasticsearch($this->configuration);
65+
/** @var Elasticsearch $elasticsearch */
66+
$elasticsearch = $this->container->get(id: 'phpmyfaq.instance.elasticsearch');
6167

6268
try {
6369
$elasticsearch->dropIndex();
@@ -77,7 +83,10 @@ public function import(): JsonResponse
7783
{
7884
$this->userHasPermission(PermissionType::CONFIGURATION_EDIT);
7985

80-
$elasticsearch = new Elasticsearch($this->configuration);
86+
/** @var Elasticsearch $elasticsearch */
87+
$elasticsearch = $this->container->get(id: 'phpmyfaq.instance.elasticsearch');
88+
89+
/** @var Faq $faq */
8190
$faq = $this->container->get(id: 'phpmyfaq.faq');
8291
$faq->getAllFaqs();
8392

@@ -113,4 +122,27 @@ public function statistics(): JsonResponse
113122
return $this->json(['error' => $e->getMessage()], Response::HTTP_BAD_REQUEST);
114123
}
115124
}
125+
126+
#[Route(
127+
path: './admin/api/elasticsearch/healthcheck',
128+
name: 'admin.api.elasticsearch.healthcheck',
129+
methods: ['GET'],
130+
)]
131+
public function healthcheck(): JsonResponse
132+
{
133+
$this->userIsAuthenticated();
134+
135+
/** @var Elasticsearch $elasticsearch */
136+
$elasticsearch = $this->container->get(id: 'phpmyfaq.instance.elasticsearch');
137+
138+
$isAvailable = $elasticsearch->isAvailable();
139+
140+
return $this->json(
141+
[
142+
'available' => $isAvailable,
143+
'status' => $isAvailable ? 'healthy' : 'unavailable',
144+
],
145+
$isAvailable ? Response::HTTP_OK : Response::HTTP_SERVICE_UNAVAILABLE,
146+
);
147+
}
116148
}

phpmyfaq/src/phpMyFAQ/Controller/Administration/Api/OpenSearchController.php

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
use phpMyFAQ\Controller\AbstractController;
2323
use phpMyFAQ\Core\Exception;
2424
use phpMyFAQ\Enums\PermissionType;
25+
use phpMyFAQ\Faq;
2526
use phpMyFAQ\Instance\OpenSearch;
2627
use phpMyFAQ\Translation;
2728
use Symfony\Component\HttpFoundation\JsonResponse;
@@ -38,7 +39,8 @@ public function create(): JsonResponse
3839
{
3940
$this->userHasPermission(PermissionType::CONFIGURATION_EDIT);
4041

41-
$openSearch = new OpenSearch($this->configuration);
42+
/* @var OpenSearch $openSearch */
43+
$openSearch = $this->container->get(id: 'phpmyfaq.instance.opensearch');
4244

4345
try {
4446
$openSearch->createIndex();
@@ -58,7 +60,8 @@ public function drop(): JsonResponse
5860
{
5961
$this->userHasPermission(PermissionType::CONFIGURATION_EDIT);
6062

61-
$openSearch = new OpenSearch($this->configuration);
63+
/* @var OpenSearch $openSearch */
64+
$openSearch = $this->container->get(id: 'phpmyfaq.instance.opensearch');
6265

6366
try {
6467
$openSearch->dropIndex();
@@ -78,7 +81,10 @@ public function import(): JsonResponse
7881
{
7982
$this->userHasPermission(PermissionType::CONFIGURATION_EDIT);
8083

81-
$openSearch = new OpenSearch($this->configuration);
84+
/* @var OpenSearch $openSearch */
85+
$openSearch = $this->container->get(id: 'phpmyfaq.instance.opensearch');
86+
87+
/* @var Faq $faq */
8288
$faq = $this->container->get(id: 'phpmyfaq.faq');
8389
$faq->getAllFaqs();
8490

@@ -91,7 +97,6 @@ public function import(): JsonResponse
9197
}
9298

9399
/**
94-
* @throws Exception
95100
* @throws \Exception
96101
*/
97102
#[Route(path: './admin/api/opensearch/statistics', name: 'admin.api.opensearch.statistics', methods: ['GET'])]
@@ -111,4 +116,26 @@ public function statistics(): JsonResponse
111116
->stats(['index' => $indexName]),
112117
], Response::HTTP_OK);
113118
}
119+
120+
/**
121+
* @throws \Exception
122+
*/
123+
#[Route(path: './admin/api/opensearch/healthcheck', name: 'admin.api.opensearch.healthcheck', methods: ['GET'])]
124+
public function healthcheck(): JsonResponse
125+
{
126+
$this->userIsAuthenticated();
127+
128+
/* @var OpenSearch $openSearch */
129+
$openSearch = $this->container->get(id: 'phpmyfaq.instance.opensearch');
130+
131+
$isAvailable = $openSearch->isAvailable();
132+
133+
return $this->json(
134+
[
135+
'available' => $isAvailable,
136+
'status' => $isAvailable ? 'healthy' : 'unavailable',
137+
],
138+
$isAvailable ? Response::HTTP_OK : Response::HTTP_SERVICE_UNAVAILABLE,
139+
);
140+
}
114141
}

phpmyfaq/src/phpMyFAQ/Instance/Elasticsearch.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -337,4 +337,19 @@ public function delete(int $solutionId): array
337337
return ['error' => $e->getMessage()];
338338
}
339339
}
340+
341+
/**
342+
* Checks if Elasticsearch is available
343+
*
344+
* @return bool
345+
*/
346+
public function isAvailable(): bool
347+
{
348+
try {
349+
return $this->client->ping()->asBool();
350+
} catch (ClientResponseException|ServerResponseException $e) {
351+
$this->configuration->getLogger()->error('Elasticsearch ping failed.', [$e->getMessage()]);
352+
return false;
353+
}
354+
}
340355
}

phpmyfaq/src/phpMyFAQ/Instance/OpenSearch.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,4 +298,19 @@ public function delete(int $solutionId): array
298298

299299
return $this->client->delete($params);
300300
}
301+
302+
/**
303+
* Checks if OpenSearch is available
304+
*
305+
* @return bool
306+
*/
307+
public function isAvailable(): bool
308+
{
309+
try {
310+
return $this->client->ping();
311+
} catch (Exception $e) {
312+
$this->configuration->getLogger()->error('OpenSearch ping failed.', [$e->getMessage()]);
313+
return false;
314+
}
315+
}
301316
}

phpmyfaq/src/services.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
use phpMyFAQ\Helper\UserHelper;
5555
use phpMyFAQ\Instance;
5656
use phpMyFAQ\Instance\Elasticsearch;
57+
use phpMyFAQ\Instance\OpenSearch;
5758
use phpMyFAQ\Language;
5859
use phpMyFAQ\Language\Plurals;
5960
use phpMyFAQ\Mail;
@@ -269,6 +270,10 @@
269270
service('phpmyfaq.configuration'),
270271
]);
271272

273+
$services->set('phpmyfaq.instance.opensearch', OpenSearch::class)->args([
274+
service('phpmyfaq.configuration'),
275+
]);
276+
272277
$services->set('phpmyfaq.language', Language::class)->args([
273278
service('phpmyfaq.configuration'),
274279
service('session'),

0 commit comments

Comments
 (0)