2828import java .util .LinkedHashMap ;
2929import java .util .Map ;
3030import java .util .Properties ;
31+ import java .util .function .Supplier ;
3132
3233import 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