-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* feat: add /health/live servlet - adds liveliness endpoint for healthcheck * feat: add DatabaseHealthCheck and HealthService - adds DatabaseHealthCheck to check db is live and ready + first tests - adds HealthService to check on all registered HealthChecks * feat: make DbConnection AutoClosable * chore: add negative test cases + refactor DatabaseHealthCheck * chore: javadoc and refactor - java doc HealthCheck interface * chore: refactor * test: HealthServletTest do not check JSON body yet * test: HealthServletTest add MariaDB container * test: HealthServletTest use container user password * feat: HealthService add isLive() + tests * feat: HealthServlet add ready/live routing - adds also DbPool startup in HealthServletTest * feat: DatabaseService check db connection for both live and ready - add tests for DatabaseService on live * test: HealthServlet test 200/500 - add test for HealthServlet when db started/not started * feat: add /health endpoint with dependencies - adds HealthResponse POJO for health JSON response - document DbPool getDatabaseConnection instance-level method - small refactors in methods naming and variables * refactor: rename HealthService.java to HealthUseCase * refactor: rename DatabaseService.java.java to DatabaseServiceDependency * refactor: DatabaseServiceDependency check ready/live after interval - update HealthServletTest to use mariadb 10.4.31 * chore: update javadoc * fix: refactor DatabaseServiceDependency and tests - fix doCheckStatus to return correct status(was returning true always) - simplify canConnectToDatabase and make it private - align tests with changes * chore: refactor HealthResponse - improve builder - add javadoc * chore: refactor HealthServlet - add logging - simplify response creation - handle unknown routes (return 404) - improve test readability * fix: fix dependency issues * feat: set content type for health endpoint response * refactor: extract polling logic to ServiceDependency class for possible reuse - cleanup DatabaseServiceDependency * chore: register dependencies as provided * chore: avoid declaring jna for all projects - found jna is needed by zmconfigd Jython and no others, directly. Was updated beacuse needed by TestContainers * chore: use new healthcheck in service * chore: avoid fork * test: HealthServletTest use container host as mysql bind address * refactor: bring back caching logic to DatabaseServiceDependency until needed by other use health checks - avoid putting caching logic on abstract class (YAGNI) * chore: JettyServerFactory add final to maps fields * chore: JettyServerFactory local host until override needed by others * test: DatabaseServiceDependencyTest remove unneeded SQLException in test * refactor: database check logic * refactor: mark response builder methods as public * refactor: simplify dependency declaration in HealthServletModule * test: add empty dependencies list test * refactor: change test names * refactor: general review and refactoring of DatabaseServiceDependencyTest * refactor: extract handler methods in HealthServlet * refactor: move dependency health summary logic in HealthUseCase * refactor: change Dependency response type * refactor: rename Dependency dto in DependencyResponse * refactor: introduce withDb utility in HealthServletTest --------- Co-authored-by: Keshav Bhatt <keshavnrj@gmail.com> Co-authored-by: Matteo Baglini <matteo.baglini@gmail.com>
- Loading branch information
1 parent
3f5fe6b
commit 237ee66
Showing
18 changed files
with
904 additions
and
33 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
67 changes: 67 additions & 0 deletions
67
store/src/main/java/com/zextras/mailbox/health/DatabaseServiceDependency.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
// SPDX-FileCopyrightText: 2023 Zextras <https://www.zextras.com> | ||
// | ||
// SPDX-License-Identifier: AGPL-3.0-only | ||
|
||
package com.zextras.mailbox.health; | ||
|
||
import com.zimbra.common.service.ServiceException; | ||
import com.zimbra.cs.db.DbPool; | ||
import com.zimbra.cs.db.DbPool.DbConnection; | ||
import java.sql.PreparedStatement; | ||
import java.sql.ResultSet; | ||
import java.sql.SQLException; | ||
import java.util.function.Supplier; | ||
|
||
/** Class represents MariaDB service dependency of mailbox */ | ||
public class DatabaseServiceDependency extends ServiceDependency { | ||
|
||
private final DbPool dbPool; | ||
private final int cacheIntervalMillis; | ||
private final Supplier<Long> currentTimeProvider; | ||
private Long lastExecMillis; | ||
private boolean lastHealthCheckedValue = false; | ||
|
||
public DatabaseServiceDependency(DbPool dbPool, Supplier<Long> currentTimeProvider) { | ||
this(dbPool, 5000, currentTimeProvider); | ||
} | ||
|
||
public DatabaseServiceDependency( | ||
DbPool dbPool, int cacheIntervalMillis, Supplier<Long> currentTimeProvider) { | ||
super("MariaDb", ServiceType.REQUIRED); | ||
this.dbPool = dbPool; | ||
this.cacheIntervalMillis = cacheIntervalMillis; | ||
this.currentTimeProvider = currentTimeProvider; | ||
} | ||
|
||
@Override | ||
public boolean isReady() { | ||
return canConnectToDatabase(); | ||
} | ||
|
||
@Override | ||
public boolean isLive() { | ||
return this.canConnectToDatabase(); | ||
} | ||
|
||
private boolean doCheckStatus() { | ||
try (DbConnection connection = dbPool.getDatabaseConnection(); | ||
PreparedStatement preparedStatement = connection.prepareStatement("SELECT 1"); | ||
ResultSet resultSet = preparedStatement.executeQuery()) { | ||
resultSet.next(); | ||
return true; | ||
} catch (ServiceException | SQLException e) { | ||
return false; | ||
} | ||
} | ||
|
||
private boolean canConnectToDatabase() { | ||
final long currentTime = currentTimeProvider.get(); | ||
|
||
if (lastExecMillis == null || currentTime > lastExecMillis + cacheIntervalMillis) { | ||
lastHealthCheckedValue = doCheckStatus(); | ||
lastExecMillis = currentTime; | ||
} | ||
|
||
return lastHealthCheckedValue; | ||
} | ||
} |
32 changes: 32 additions & 0 deletions
32
store/src/main/java/com/zextras/mailbox/health/DependencyHealthResult.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
package com.zextras.mailbox.health; | ||
|
||
public class DependencyHealthResult { | ||
private final String name; | ||
private final ServiceDependency.ServiceType type; | ||
private final boolean ready; | ||
private final boolean live; | ||
|
||
public DependencyHealthResult( | ||
String name, ServiceDependency.ServiceType type, boolean ready, boolean live) { | ||
this.name = name; | ||
this.type = type; | ||
this.ready = ready; | ||
this.live = live; | ||
} | ||
|
||
public String getName() { | ||
return name; | ||
} | ||
|
||
public ServiceDependency.ServiceType getType() { | ||
return type; | ||
} | ||
|
||
public boolean isReady() { | ||
return ready; | ||
} | ||
|
||
public boolean isLive() { | ||
return live; | ||
} | ||
} |
27 changes: 27 additions & 0 deletions
27
store/src/main/java/com/zextras/mailbox/health/HealthStatus.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
// SPDX-FileCopyrightText: 2023 Zextras <https://www.zextras.com> | ||
// | ||
// SPDX-License-Identifier: AGPL-3.0-only | ||
|
||
package com.zextras.mailbox.health; | ||
|
||
/** | ||
* Contract for checking the health status of a service. | ||
*/ | ||
public interface HealthStatus { | ||
|
||
/** | ||
* Checks if the service is ready to process requests. | ||
* | ||
* @return {@code true} if the service is ready to receive requests, otherwise {@code false} | ||
*/ | ||
boolean isReady(); | ||
|
||
/** | ||
* Checks if the service is live and responsive. If the liveliness check fails, it indicates that | ||
* the service is unhealthy or dead and should be restarted. | ||
* | ||
* @return {@code true} if the service is healthy and responsive, otherwise {@code false} | ||
*/ | ||
boolean isLive(); | ||
} | ||
|
37 changes: 37 additions & 0 deletions
37
store/src/main/java/com/zextras/mailbox/health/HealthUseCase.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
// SPDX-FileCopyrightText: 2023 Zextras <https://www.zextras.com> | ||
// | ||
// SPDX-License-Identifier: AGPL-3.0-only | ||
|
||
package com.zextras.mailbox.health; | ||
|
||
import java.util.List; | ||
import java.util.stream.Collectors; | ||
import javax.inject.Inject; | ||
|
||
public class HealthUseCase { | ||
|
||
private final List<ServiceDependency> serviceDependencies; | ||
|
||
@Inject | ||
public HealthUseCase(List<ServiceDependency> serviceDependencies) { | ||
this.serviceDependencies = serviceDependencies; | ||
} | ||
|
||
public boolean isReady() { | ||
return serviceDependencies.stream().allMatch(ServiceDependency::isReady); | ||
} | ||
|
||
public List<DependencyHealthResult> dependenciesHealthSummary() { | ||
return serviceDependencies.stream() | ||
.map(x -> createHealthResult(x)) | ||
.collect(Collectors.toList()); | ||
} | ||
|
||
public boolean isLive() { | ||
return serviceDependencies.stream().allMatch(ServiceDependency::isLive); | ||
} | ||
|
||
private DependencyHealthResult createHealthResult(ServiceDependency x) { | ||
return new DependencyHealthResult(x.getName(), x.getType(), x.isReady(), x.isLive()); | ||
} | ||
} |
36 changes: 36 additions & 0 deletions
36
store/src/main/java/com/zextras/mailbox/health/ServiceDependency.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
// SPDX-FileCopyrightText: 2023 Zextras <https://www.zextras.com> | ||
// | ||
// SPDX-License-Identifier: AGPL-3.0-only | ||
|
||
package com.zextras.mailbox.health; | ||
|
||
/** | ||
* Abstract class representing service as dependency of another service. | ||
*/ | ||
public abstract class ServiceDependency implements HealthStatus { | ||
|
||
private final String name; | ||
private final ServiceType type; | ||
|
||
|
||
protected ServiceDependency(String name, | ||
ServiceType type) { | ||
this.name = name; | ||
this.type = type; | ||
} | ||
|
||
public String getName() { | ||
return name; | ||
} | ||
|
||
public ServiceType getType() { | ||
return type; | ||
} | ||
|
||
public enum ServiceType { | ||
OPTIONAL, | ||
REQUIRED | ||
} | ||
} | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.