From 5ea7816f39b0d5980a1fb7c6d22c3e6b63a4a813 Mon Sep 17 00:00:00 2001 From: Damodar Lohani Date: Wed, 3 Jun 2026 02:51:23 +0000 Subject: [PATCH 1/2] feat: add ping() to audit adapters for connectivity checks Add a ping() health probe mirroring utopia-php/database: - Adapter: declare abstract ping(): bool - ClickHouse: run `SELECT 1` over the HTTP interface, return true on success - Database: delegate to the underlying Utopia\Database ping() - Audit: facade passthrough to the adapter - Tests: assert ping() in the shared AuditBase suite (both adapters) Co-Authored-By: Claude Opus 4.8 --- src/Audit/Adapter.php | 9 +++++++++ src/Audit/Adapter/ClickHouse.php | 14 ++++++++++++++ src/Audit/Adapter/Database.php | 12 ++++++++++++ src/Audit/Audit.php | 12 ++++++++++++ tests/Audit/AuditBase.php | 5 +++++ 5 files changed, 52 insertions(+) diff --git a/src/Audit/Adapter.php b/src/Audit/Adapter.php index 33f0d8b..35a4ab1 100644 --- a/src/Audit/Adapter.php +++ b/src/Audit/Adapter.php @@ -239,4 +239,13 @@ abstract public function find(array $queries = []): array; * @throws \Exception */ abstract public function count(array $queries = [], ?int $max = null): int; + + /** + * Ping the adapter to check connectivity. + * + * @return bool + * + * @throws \Exception + */ + abstract public function ping(): bool; } diff --git a/src/Audit/Adapter/ClickHouse.php b/src/Audit/Adapter/ClickHouse.php index d96327b..ddbe54b 100644 --- a/src/Audit/Adapter/ClickHouse.php +++ b/src/Audit/Adapter/ClickHouse.php @@ -113,6 +113,20 @@ public function getName(): string return 'ClickHouse'; } + /** + * Ping ClickHouse to check connectivity. + * + * @return bool + * + * @throws Exception + */ + public function ping(): bool + { + $result = $this->query('SELECT 1 FORMAT TabSeparated'); + + return trim($result) === '1'; + } + /** * Validate host parameter. * diff --git a/src/Audit/Adapter/Database.php b/src/Audit/Adapter/Database.php index cda3383..baba0bd 100644 --- a/src/Audit/Adapter/Database.php +++ b/src/Audit/Adapter/Database.php @@ -34,6 +34,18 @@ public function getName(): string return 'Database'; } + /** + * Ping the database to check connectivity. + * + * @return bool + * + * @throws \Exception + */ + public function ping(): bool + { + return $this->db->ping(); + } + /** * Setup database structure. * diff --git a/src/Audit/Audit.php b/src/Audit/Audit.php index bd51560..54049b6 100644 --- a/src/Audit/Audit.php +++ b/src/Audit/Audit.php @@ -287,4 +287,16 @@ public function count(array $queries = [], ?int $max = null): int { return $this->adapter->count($queries, $max); } + + /** + * Ping the adapter to check connectivity. + * + * @return bool + * + * @throws \Exception + */ + public function ping(): bool + { + return $this->adapter->ping(); + } } diff --git a/tests/Audit/AuditBase.php b/tests/Audit/AuditBase.php index 30531b1..4ba7c74 100644 --- a/tests/Audit/AuditBase.php +++ b/tests/Audit/AuditBase.php @@ -62,6 +62,11 @@ public function createLogs(): void $this->assertInstanceOf('Utopia\\Audit\\Log', $this->audit->log(null, 'insert', 'user/null', $userAgent, $ip, $dataWithAttributes)); } + public function testPing(): void + { + $this->assertTrue($this->audit->ping()); + } + public function testGetLogsByUser(): void { $logs = $this->audit->getLogsByUser('userId'); From d22d485adb304706d235e67d132b2a55d1e394e4 Mon Sep 17 00:00:00 2001 From: Damodar Lohani Date: Wed, 3 Jun 2026 03:32:07 +0000 Subject: [PATCH 2/2] refactor: use native /ping endpoint, return false on failure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Address review feedback on ping(): - ClickHouse: probe the dedicated /ping endpoint instead of running SELECT 1 through the query pipeline — lighter, needs no database context, and stays out of query logs - ClickHouse + Database: catch connectivity errors and return false so ping(): bool honors the health-check contract instead of throwing - Update docblocks to document the no-throw, false-on-failure behavior Co-Authored-By: Claude Opus 4.8 --- src/Audit/Adapter.php | 4 ++-- src/Audit/Adapter/ClickHouse.php | 17 +++++++++++++---- src/Audit/Adapter/Database.php | 10 +++++++--- src/Audit/Audit.php | 4 ++-- 4 files changed, 24 insertions(+), 11 deletions(-) diff --git a/src/Audit/Adapter.php b/src/Audit/Adapter.php index 35a4ab1..131e2ba 100644 --- a/src/Audit/Adapter.php +++ b/src/Audit/Adapter.php @@ -243,9 +243,9 @@ abstract public function count(array $queries = [], ?int $max = null): int; /** * Ping the adapter to check connectivity. * - * @return bool + * Returns false on any connectivity failure rather than throwing. * - * @throws \Exception + * @return bool True when the backing store is reachable, false otherwise. */ abstract public function ping(): bool; } diff --git a/src/Audit/Adapter/ClickHouse.php b/src/Audit/Adapter/ClickHouse.php index ddbe54b..c0ee9b7 100644 --- a/src/Audit/Adapter/ClickHouse.php +++ b/src/Audit/Adapter/ClickHouse.php @@ -116,15 +116,24 @@ public function getName(): string /** * Ping ClickHouse to check connectivity. * - * @return bool + * Uses ClickHouse's dedicated /ping endpoint, which bypasses the query + * pipeline, requires no database context, and is not recorded in query + * logs. Returns false on any connectivity failure rather than throwing. * - * @throws Exception + * @return bool True when ClickHouse is reachable, false otherwise. */ public function ping(): bool { - $result = $this->query('SELECT 1 FORMAT TabSeparated'); + $scheme = $this->secure ? 'https' : 'http'; + $url = "{$scheme}://{$this->host}:{$this->port}/ping"; + + try { + $response = $this->client->fetch(url: $url, method: Client::METHOD_GET); + } catch (\Throwable) { + return false; + } - return trim($result) === '1'; + return $response->getStatusCode() === 200; } /** diff --git a/src/Audit/Adapter/Database.php b/src/Audit/Adapter/Database.php index baba0bd..2c0f780 100644 --- a/src/Audit/Adapter/Database.php +++ b/src/Audit/Adapter/Database.php @@ -37,13 +37,17 @@ public function getName(): string /** * Ping the database to check connectivity. * - * @return bool + * Returns false on any connectivity failure rather than throwing. * - * @throws \Exception + * @return bool True when the database is reachable, false otherwise. */ public function ping(): bool { - return $this->db->ping(); + try { + return $this->db->ping(); + } catch (\Throwable) { + return false; + } } /** diff --git a/src/Audit/Audit.php b/src/Audit/Audit.php index 54049b6..0cd52c6 100644 --- a/src/Audit/Audit.php +++ b/src/Audit/Audit.php @@ -291,9 +291,9 @@ public function count(array $queries = [], ?int $max = null): int /** * Ping the adapter to check connectivity. * - * @return bool + * Returns false on any connectivity failure rather than throwing. * - * @throws \Exception + * @return bool True when the backing store is reachable, false otherwise. */ public function ping(): bool {