Skip to content

Commit 98f92e1

Browse files
committed
refactor: eliminate code duplication in health checks
1 parent 753bdc0 commit 98f92e1

1 file changed

Lines changed: 67 additions & 115 deletions

File tree

src/main/java/com/iemr/admin/service/health/HealthService.java

Lines changed: 67 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import java.util.LinkedHashMap;
2929
import java.util.Map;
3030
import java.util.Properties;
31+
import java.util.function.Supplier;
3132

3233
import javax.sql.DataSource;
3334

@@ -83,15 +84,15 @@ public Map<String, Object> checkHealth() {
8384
// Check MySQL connectivity
8485
Map<String, Object> mysqlStatus = checkMySQLHealth();
8586
components.put("mysql", mysqlStatus);
86-
if (!"UP".equals(mysqlStatus.get("status"))) {
87+
if (!isHealthy(mysqlStatus)) {
8788
overallHealth = false;
8889
}
8990

9091
// Check Redis connectivity if configured
9192
if (redisTemplate != null) {
9293
Map<String, Object> redisStatus = checkRedisHealth();
9394
components.put("redis", redisStatus);
94-
if (!"UP".equals(redisStatus.get("status"))) {
95+
if (!isHealthy(redisStatus)) {
9596
overallHealth = false;
9697
}
9798
}
@@ -100,7 +101,7 @@ public Map<String, Object> checkHealth() {
100101
if (mongoTemplate != null) {
101102
Map<String, Object> mongoStatus = checkMongoDBHealth();
102103
components.put("mongodb", mongoStatus);
103-
if (!"UP".equals(mongoStatus.get("status"))) {
104+
if (!isHealthy(mongoStatus)) {
104105
overallHealth = false;
105106
}
106107
}
@@ -114,144 +115,94 @@ public Map<String, Object> checkHealth() {
114115
}
115116

116117
private Map<String, Object> checkMySQLHealth() {
117-
Map<String, Object> status = new LinkedHashMap<>();
118118
Map<String, Object> details = new LinkedHashMap<>();
119-
long startTime = System.currentTimeMillis();
120-
121-
// Add connection details
122119
details.put("type", "MySQL");
123120
details.put("host", extractHost(dbUrl));
124121
details.put("port", extractPort(dbUrl));
125122
details.put("database", extractDatabaseName(dbUrl));
126123

127-
try (Connection connection = dataSource.getConnection()) {
128-
// 2 second timeout per best practices
129-
boolean isConnectionValid = connection.isValid(2);
130-
131-
if (isConnectionValid) {
132-
// 3 second query timeout
133-
try (PreparedStatement stmt = connection.prepareStatement(DB_HEALTH_CHECK_QUERY)) {
134-
stmt.setQueryTimeout(3);
135-
try (ResultSet rs = stmt.executeQuery()) {
136-
if (rs.next() && rs.getInt(1) == 1) {
137-
long responseTime = System.currentTimeMillis() - startTime;
138-
logger.debug("MySQL health check: UP ({}ms)", responseTime);
139-
140-
status.put("status", "UP");
141-
details.put("responseTimeMs", responseTime);
142-
143-
// Get database version
144-
String version = getMySQLVersion(connection);
145-
if (version != null) {
146-
details.put("version", version);
124+
return performHealthCheck("MySQL", details, () -> {
125+
try (Connection connection = dataSource.getConnection()) {
126+
if (connection.isValid(2)) {
127+
try (PreparedStatement stmt = connection.prepareStatement(DB_HEALTH_CHECK_QUERY)) {
128+
stmt.setQueryTimeout(3);
129+
try (ResultSet rs = stmt.executeQuery()) {
130+
if (rs.next() && rs.getInt(1) == 1) {
131+
String version = getMySQLVersion(connection);
132+
return new HealthCheckResult(true, version, null);
147133
}
148-
149-
status.put("details", details);
150-
return status;
151134
}
152135
}
153136
}
137+
return new HealthCheckResult(false, null, "Connection validation failed");
154138
}
155-
logger.warn("MySQL health check: Connection not valid");
156-
status.put("status", "DOWN");
157-
details.put("error", "Connection validation failed");
158-
status.put("details", details);
159-
return status;
160-
} catch (Exception e) {
161-
logger.error("MySQL health check failed: {}", e.getMessage());
162-
status.put("status", "DOWN");
163-
details.put("error", e.getMessage());
164-
details.put("errorType", e.getClass().getSimpleName());
165-
status.put("details", details);
166-
return status;
167-
}
139+
});
168140
}
169141

170142
private Map<String, Object> checkRedisHealth() {
171-
Map<String, Object> status = new LinkedHashMap<>();
172143
Map<String, Object> details = new LinkedHashMap<>();
173-
long startTime = System.currentTimeMillis();
174-
175-
// Add connection details
176144
details.put("type", "Redis");
177145
details.put("host", redisHost);
178146
details.put("port", redisPort);
179147

180-
try {
181-
// Use ping() from RedisConnection directly
148+
return performHealthCheck("Redis", details, () -> {
182149
String pong = redisTemplate.execute((RedisCallback<String>) connection ->
183150
connection.ping()
184151
);
185-
186152
if ("PONG".equals(pong)) {
187-
long responseTime = System.currentTimeMillis() - startTime;
188-
logger.debug("Redis health check: UP ({}ms)", responseTime);
189-
190-
status.put("status", "UP");
191-
details.put("responseTimeMs", responseTime);
192-
193-
// Get Redis version
194153
String version = getRedisVersion();
195-
if (version != null) {
196-
details.put("version", version);
197-
}
198-
199-
status.put("details", details);
200-
return status;
154+
return new HealthCheckResult(true, version, null);
201155
}
202-
logger.warn("Redis health check: Ping returned unexpected response");
203-
status.put("status", "DOWN");
204-
details.put("error", "Ping returned unexpected response");
205-
status.put("details", details);
206-
return status;
207-
} catch (Exception e) {
208-
logger.error("Redis health check failed: {}", e.getMessage());
209-
status.put("status", "DOWN");
210-
details.put("error", e.getMessage());
211-
details.put("errorType", e.getClass().getSimpleName());
212-
status.put("details", details);
213-
return status;
214-
}
156+
return new HealthCheckResult(false, null, "Ping returned unexpected response");
157+
});
215158
}
216159

217160
private Map<String, Object> checkMongoDBHealth() {
218-
Map<String, Object> status = new LinkedHashMap<>();
219161
Map<String, Object> details = new LinkedHashMap<>();
220-
long startTime = System.currentTimeMillis();
221-
222-
// Add connection details
223162
details.put("type", "MongoDB");
224163
details.put("host", mongoHost);
225164
details.put("port", mongoPort);
226165
details.put("database", mongoDatabase);
227166

228-
try {
229-
// Run ping command to check MongoDB connectivity
167+
return performHealthCheck("MongoDB", details, () -> {
230168
Document pingResult = mongoTemplate.getDb().runCommand(new Document("ping", 1));
231-
232169
if (pingResult != null && pingResult.getDouble("ok") == 1.0) {
233-
long responseTime = System.currentTimeMillis() - startTime;
234-
logger.debug("MongoDB health check: UP ({}ms)", responseTime);
170+
String version = getMongoDBVersion();
171+
return new HealthCheckResult(true, version, null);
172+
}
173+
return new HealthCheckResult(false, null, "Ping returned unexpected response");
174+
});
175+
}
235176

177+
/**
178+
* Common health check execution pattern to reduce code duplication.
179+
*/
180+
private Map<String, Object> performHealthCheck(String componentName,
181+
Map<String, Object> details,
182+
Supplier<HealthCheckResult> checker) {
183+
Map<String, Object> status = new LinkedHashMap<>();
184+
long startTime = System.currentTimeMillis();
185+
186+
try {
187+
HealthCheckResult result = checker.get();
188+
long responseTime = System.currentTimeMillis() - startTime;
189+
190+
if (result.isHealthy) {
191+
logger.debug("{} health check: UP ({}ms)", componentName, responseTime);
236192
status.put("status", "UP");
237193
details.put("responseTimeMs", responseTime);
238-
239-
// Get MongoDB version
240-
String version = getMongoDBVersion();
241-
if (version != null) {
242-
details.put("version", version);
194+
if (result.version != null) {
195+
details.put("version", result.version);
243196
}
244-
245-
status.put("details", details);
246-
return status;
197+
} else {
198+
logger.warn("{} health check: {}", componentName, result.error);
199+
status.put("status", "DOWN");
200+
details.put("error", result.error);
247201
}
248-
logger.warn("MongoDB health check: Ping returned unexpected response");
249-
status.put("status", "DOWN");
250-
details.put("error", "Ping returned unexpected response");
251202
status.put("details", details);
252203
return status;
253204
} catch (Exception e) {
254-
logger.error("MongoDB health check failed: {}", e.getMessage());
205+
logger.error("{} health check failed: {}", componentName, e.getMessage());
255206
status.put("status", "DOWN");
256207
details.put("error", e.getMessage());
257208
details.put("errorType", e.getClass().getSimpleName());
@@ -260,6 +211,10 @@ private Map<String, Object> checkMongoDBHealth() {
260211
}
261212
}
262213

214+
private boolean isHealthy(Map<String, Object> componentStatus) {
215+
return "UP".equals(componentStatus.get("status"));
216+
}
217+
263218
private String getMySQLVersion(Connection connection) {
264219
try (PreparedStatement stmt = connection.prepareStatement(DB_VERSION_QUERY);
265220
ResultSet rs = stmt.executeQuery()) {
@@ -298,23 +253,16 @@ private String getMongoDBVersion() {
298253
return null;
299254
}
300255

301-
/**
302-
* Extracts host from JDBC URL.
303-
* Example: jdbc:mysql://mysql-container:3306/db_iemr -> mysql-container
304-
*/
305256
private String extractHost(String jdbcUrl) {
306257
if (jdbcUrl == null || "unknown".equals(jdbcUrl)) {
307258
return "unknown";
308259
}
309260
try {
310-
// Remove jdbc:mysql:// prefix
311261
String withoutPrefix = jdbcUrl.replaceFirst("jdbc:mysql://", "");
312-
// Get host:port part (before the first /)
313262
int slashIndex = withoutPrefix.indexOf('/');
314263
String hostPort = slashIndex > 0
315264
? withoutPrefix.substring(0, slashIndex)
316265
: withoutPrefix;
317-
// Get host (before the colon)
318266
int colonIndex = hostPort.indexOf(':');
319267
return colonIndex > 0 ? hostPort.substring(0, colonIndex) : hostPort;
320268
} catch (Exception e) {
@@ -323,23 +271,16 @@ private String extractHost(String jdbcUrl) {
323271
return "unknown";
324272
}
325273

326-
/**
327-
* Extracts port from JDBC URL.
328-
* Example: jdbc:mysql://mysql-container:3306/db_iemr -> 3306
329-
*/
330274
private String extractPort(String jdbcUrl) {
331275
if (jdbcUrl == null || "unknown".equals(jdbcUrl)) {
332276
return "unknown";
333277
}
334278
try {
335-
// Remove jdbc:mysql:// prefix
336279
String withoutPrefix = jdbcUrl.replaceFirst("jdbc:mysql://", "");
337-
// Get host:port part (before the first /)
338280
int slashIndex = withoutPrefix.indexOf('/');
339281
String hostPort = slashIndex > 0
340282
? withoutPrefix.substring(0, slashIndex)
341283
: withoutPrefix;
342-
// Get port (after the colon)
343284
int colonIndex = hostPort.indexOf(':');
344285
return colonIndex > 0 ? hostPort.substring(colonIndex + 1) : "3306";
345286
} catch (Exception e) {
@@ -348,10 +289,6 @@ private String extractPort(String jdbcUrl) {
348289
return "3306";
349290
}
350291

351-
/**
352-
* Extracts database name from JDBC URL.
353-
* Example: jdbc:mysql://mysql-container:3306/db_iemr?params -> db_iemr
354-
*/
355292
private String extractDatabaseName(String jdbcUrl) {
356293
if (jdbcUrl == null || "unknown".equals(jdbcUrl)) {
357294
return "unknown";
@@ -371,4 +308,19 @@ private String extractDatabaseName(String jdbcUrl) {
371308
}
372309
return "unknown";
373310
}
311+
312+
/**
313+
* Internal class to hold health check results.
314+
*/
315+
private static class HealthCheckResult {
316+
final boolean isHealthy;
317+
final String version;
318+
final String error;
319+
320+
HealthCheckResult(boolean isHealthy, String version, String error) {
321+
this.isHealthy = isHealthy;
322+
this.version = version;
323+
this.error = error;
324+
}
325+
}
374326
}

0 commit comments

Comments
 (0)