Skip to content

Conversation

@Suraj-kumar00
Copy link
Contributor

@Suraj-kumar00 Suraj-kumar00 commented Jan 13, 2026

📋 Description

  • Enhanced /health endpoint to show per-component status
  • Added type, host, port, database, version, and response time details
  • Returns error messages and types when components are down
  • Added MongoDB dependency and health check support

JIRA ID:

Please provide a summary of the change and the motivation behind it. Include relevant context and details.


✅ Type of Change

  • 🐞 Bug fix (non-breaking change which resolves an issue)
  • New feature (non-breaking change which adds functionality)
  • 🔥 Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • 🛠 Refactor (change that is neither a fix nor a new feature)
  • ⚙️ Config change (configuration file or build script updates)
  • 📚 Documentation (updates to docs or readme)
  • 🧪 Tests (adding new or updating existing tests)
  • 🎨 UI/UX (changes that affect the user interface)
  • 🚀 Performance (improves performance)
  • 🧹 Chore (miscellaneous changes that don't modify src or test files)

ℹ️ Additional Information

Screenshot 2026-01-14 at 12 58 57 AM

Please describe how the changes were tested, and include any relevant screenshots, logs, or other information that provides additional context.

Summary by CodeRabbit

  • New Features

    • Enhanced health checks with per-component reporting for MySQL, Redis, and MongoDB, including status, response times, versions and connection details.
    • Added MongoDB integration to the application.
  • Chores

    • Improved CI workflow to ensure accurate base-branch references during commit linting.

✏️ Tip: You can customize this high-level summary in your review settings.

- Enhanced /health endpoint to show per-component status
- Added type, host, port, database, version, and response time details
- Returns error messages and types when components are down
- Added MongoDB dependency and health check support
@coderabbitai
Copy link

coderabbitai bot commented Jan 13, 2026

📝 Walkthrough

Walkthrough

Added MongoDB support and extended the health endpoint to perform component-level checks (MySQL, Redis, MongoDB) with timestamps and versions; introduced Spring Data MongoDB dependency and config; and added a GitHub Actions step to fetch the PR base branch for commit-lint comparisons.

Changes

Cohort / File(s) Summary
MongoDB Integration Setup
pom.xml, src/main/resources/application.properties
Added org.springframework.boot:spring-boot-starter-data-mongodb and configured MongoDB properties (spring.data.mongodb.host, spring.data.mongodb.port, spring.data.mongodb.database).
Enhanced Health Service
src/main/java/com/iemr/admin/service/health/HealthService.java
Rewrote health endpoint to aggregate component checks (MySQL, Redis, MongoDB) using LinkedHashMap, added per-component check methods, responseTime/version/error details, JDBC URL parsing helpers, and centralized performHealthCheck logic.
CI/CD Workflow
.github/workflows/commit-lint.yml
Added "Fetch base branch" step to fetch base branch refs from origin (placed between checkout and Node.js setup) so base SHA is available for comparisons.

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant HealthService
  participant MySQL
  participant Redis
  participant MongoDB

  Client->>HealthService: GET /health
  HealthService->>MySQL: perform MySQL health check (query/version)
  MySQL-->>HealthService: status, version, responseTime
  HealthService->>Redis: perform Redis ping/version
  Redis-->>HealthService: status, version, responseTime
  HealthService->>MongoDB: perform MongoDB ping/version
  MongoDB-->>HealthService: status, version, responseTime
  HealthService->>HealthService: aggregate component statuses, compute overall status, timestamp
  HealthService-->>Client: JSON health payload (timestamp, status, components...)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 A hop, a ping, a MongoDB cheer—
I checked the stores both far and near.
Versions, times, and status bright,
CI fetched refs to keep things right.
Healthy hops all through the night! 🥕

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 7.69% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the primary change: adding detailed component health checks for MySQL, Redis, and MongoDB, which is the main focus of the HealthService.java modifications and supporting changes.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@Suraj-kumar00 Suraj-kumar00 changed the title Contributor/suraj feat: add detailed component health checks for MySQL, Redis, and MongoDB Jan 13, 2026
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In @src/main/java/com/iemr/admin/service/health/HealthService.java:
- Around line 230-232: The ping check in HealthService uses
pingResult.getDouble("ok") which can throw ClassCastException if "ok" is an
Integer; change the check to safely handle numeric types by retrieving "ok" as a
Number (e.g., pingResult.get("ok", Number.class) or cast to Number) and compare
its doubleValue() to 1.0 (or compare number.intValue() == 1) after null-checking
pingResult; update the condition around mongoTemplate.getDb().runCommand(...) to
use this safe numeric comparison.
🧹 Nitpick comments (3)
src/main/resources/application.properties (1)

78-81: Consider adding MongoDB authentication configuration.

The MongoDB configuration lacks authentication credentials (spring.data.mongodb.username, spring.data.mongodb.password, spring.data.mongodb.authentication-database). While this may be acceptable for the test profile (line 10), ensure that environment-specific property files for production include proper authentication and consider TLS settings (spring.data.mongodb.ssl.enabled).

src/main/java/com/iemr/admin/service/health/HealthService.java (2)

180-184: Consider adding a timeout for Redis operations.

Unlike the MySQL health check which has explicit timeouts, the Redis ping operation doesn't have a timeout configured. If Redis is unresponsive, this could block the health check thread indefinitely. Consider configuring spring.redis.timeout in application properties or wrapping the operation with a timeout.


305-349: Consider extracting common URL parsing logic to reduce duplication.

extractHost and extractPort share identical logic for prefix removal and hostPort extraction (lines 311-316 and 336-341). Consider extracting this to a helper method for maintainability.

♻️ Suggested refactor
+    private String extractHostPort(String jdbcUrl) {
+        if (jdbcUrl == null || "unknown".equals(jdbcUrl)) {
+            return null;
+        }
+        try {
+            String withoutPrefix = jdbcUrl.replaceFirst("jdbc:mysql://", "");
+            int slashIndex = withoutPrefix.indexOf('/');
+            return slashIndex > 0 ? withoutPrefix.substring(0, slashIndex) : withoutPrefix;
+        } catch (Exception e) {
+            return null;
+        }
+    }
+
     private String extractHost(String jdbcUrl) {
-        if (jdbcUrl == null || "unknown".equals(jdbcUrl)) {
-            return "unknown";
-        }
-        try {
-            String withoutPrefix = jdbcUrl.replaceFirst("jdbc:mysql://", "");
-            int slashIndex = withoutPrefix.indexOf('/');
-            String hostPort = slashIndex > 0 
-                ? withoutPrefix.substring(0, slashIndex) 
-                : withoutPrefix;
+        String hostPort = extractHostPort(jdbcUrl);
+        if (hostPort == null) return "unknown";
+        try {
             int colonIndex = hostPort.indexOf(':');
             return colonIndex > 0 ? hostPort.substring(0, colonIndex) : hostPort;
         } catch (Exception e) {
-            logger.debug("Could not extract host from URL: {}", e.getMessage());
+            return "unknown";
         }
-        return "unknown";
     }
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c56ce2d and 753bdc0.

📒 Files selected for processing (4)
  • .github/workflows/commit-lint.yml
  • pom.xml
  • src/main/java/com/iemr/admin/service/health/HealthService.java
  • src/main/resources/application.properties
🔇 Additional comments (6)
.github/workflows/commit-lint.yml (1)

20-22: LGTM! Proper base branch fetching for commitlint.

This step correctly fetches the base branch to ensure commitlint --from can access the base SHA. The fetch-depth: 0 in the checkout step combined with this fetch ensures the full commit history is available for comparison.

pom.xml (1)

203-206: LGTM!

The MongoDB starter dependency is correctly added without an explicit version, allowing Spring Boot's dependency management (via spring-boot-starter-parent:3.2.2) to resolve a compatible version.

src/main/java/com/iemr/admin/service/health/HealthService.java (4)

54-77: LGTM! Good use of optional autowiring and configuration defaults.

The @Autowired(required = false) for both RedisTemplate and MongoTemplate correctly handles scenarios where these datastores are not configured. The @Value annotations with sensible defaults ensure the service doesn't fail if properties are missing.


78-114: LGTM! Clean health aggregation logic.

The method correctly aggregates component health statuses and marks overall status as DOWN if any component fails. The null checks for redisTemplate and mongoTemplate properly handle optional datastores.


116-168: LGTM! Robust MySQL health check with proper resource management.

Good implementation with:

  • Try-with-resources for automatic connection and statement cleanup
  • Reasonable timeouts (2s for connection validation, 3s for query)
  • Comprehensive error details including exception type
  • Connection validation before executing the health check query

263-299: LGTM! Defensive version retrieval with graceful fallback.

All three version retrieval methods properly catch exceptions and log at debug level (appropriate since version info is supplementary). Returning null on failure is correctly handled by the callers with null checks before adding to details.

@sonarqubecloud
Copy link

@Suraj-kumar00
Copy link
Contributor Author

Hi @vanitha1822 and @vishwab1
Please review.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In @src/main/java/com/iemr/admin/service/health/HealthService.java:
- Around line 171-178: The MongoDB health check may NPE by unboxing a null from
pingResult.getDouble("ok") and uses fragile equality; update the lambda in
performHealthCheck to first verify pingResult is non-null and contains the "ok"
key, retrieve the value as a Number (e.g., Number okVal = (Number)
pingResult.get("ok")) or via getDouble with null-check, ensure okVal != null,
then use Double.compare(okVal.doubleValue(), 1.0) == 0 or a tolerance (e.g., >=
0.999) to decide success; if the key is missing or the value indicates failure
return new HealthCheckResult(false, null, "Ping returned unexpected or missing
ok value") and keep getMongoDBVersion() and HealthCheckResult usage unchanged.
🧹 Nitpick comments (1)
src/main/java/com/iemr/admin/service/health/HealthService.java (1)

190-215: Response time not recorded for failed health checks.

responseTimeMs is only added when the check succeeds. Recording response time for failures would help diagnose timeout vs immediate failure scenarios.

Proposed improvement
         try {
             HealthCheckResult result = checker.get();
             long responseTime = System.currentTimeMillis() - startTime;
+            details.put("responseTimeMs", responseTime);

             if (result.isHealthy) {
                 logger.debug("{} health check: UP ({}ms)", componentName, responseTime);
                 status.put("status", "UP");
-                details.put("responseTimeMs", responseTime);
                 if (result.version != null) {
                     details.put("version", result.version);
                 }
             } else {
                 logger.warn("{} health check: {}", componentName, result.error);
                 status.put("status", "DOWN");
                 details.put("error", result.error);
             }
             status.put("details", details);
             return status;
         } catch (Exception e) {
+            long responseTime = System.currentTimeMillis() - startTime;
             logger.error("{} health check failed: {}", componentName, e.getMessage());
             status.put("status", "DOWN");
             details.put("error", e.getMessage());
             details.put("errorType", e.getClass().getSimpleName());
+            details.put("responseTimeMs", responseTime);
             status.put("details", details);
             return status;
         }
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 753bdc0 and c3dc907.

📒 Files selected for processing (1)
  • src/main/java/com/iemr/admin/service/health/HealthService.java
🔇 Additional comments (3)
src/main/java/com/iemr/admin/service/health/HealthService.java (3)

316-329: LGTM!

Clean internal result holder. If targeting Java 16+, this could be simplified to a record, but the current implementation is perfectly fine.


79-115: Well-structured health aggregation.

Good use of LinkedHashMap for predictable JSON ordering, conditional component checks based on template availability, and clean aggregation of overall status. The timestamp using Instant.now().toString() produces ISO-8601 format which is appropriate for APIs.


260-276: No issue: URL parsing is appropriately MySQL-specific.

The application consistently uses com.mysql.cj.jdbc.Driver across all environment configurations (admin_ci.properties, admin_docker.properties, admin_example.properties). The extractHost, extractPort, and extractDatabaseName methods are correctly hardcoded for the jdbc:mysql:// format that matches the actual JDBC driver in use. The specificity is intentional and appropriate for this codebase's design.

Likely an incorrect or invalid review comment.

Comment on lines +171 to +178
return performHealthCheck("MongoDB", details, () -> {
Document pingResult = mongoTemplate.getDb().runCommand(new Document("ping", 1));
if (pingResult != null && pingResult.getDouble("ok") == 1.0) {
String version = getMongoDBVersion();
return new HealthCheckResult(true, version, null);
}
return new HealthCheckResult(false, null, "Ping returned unexpected response");
});
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Potential NullPointerException on MongoDB health check.

Document.getDouble("ok") returns a Double wrapper that can be null if the key doesn't exist. Unboxing a null Double for comparison with 1.0 will throw NPE. Additionally, floating-point equality comparisons are fragile.

Proposed fix
         return performHealthCheck("MongoDB", details, () -> {
             Document pingResult = mongoTemplate.getDb().runCommand(new Document("ping", 1));
-            if (pingResult != null && pingResult.getDouble("ok") == 1.0) {
+            if (pingResult != null) {
+                Double okValue = pingResult.getDouble("ok");
+                if (okValue != null && okValue >= 1.0) {
                     String version = getMongoDBVersion();
                     return new HealthCheckResult(true, version, null);
+                }
             }
             return new HealthCheckResult(false, null, "Ping returned unexpected response");
         });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
return performHealthCheck("MongoDB", details, () -> {
Document pingResult = mongoTemplate.getDb().runCommand(new Document("ping", 1));
if (pingResult != null && pingResult.getDouble("ok") == 1.0) {
String version = getMongoDBVersion();
return new HealthCheckResult(true, version, null);
}
return new HealthCheckResult(false, null, "Ping returned unexpected response");
});
return performHealthCheck("MongoDB", details, () -> {
Document pingResult = mongoTemplate.getDb().runCommand(new Document("ping", 1));
if (pingResult != null) {
Double okValue = pingResult.getDouble("ok");
if (okValue != null && okValue >= 1.0) {
String version = getMongoDBVersion();
return new HealthCheckResult(true, version, null);
}
}
return new HealthCheckResult(false, null, "Ping returned unexpected response");
});
🤖 Prompt for AI Agents
In @src/main/java/com/iemr/admin/service/health/HealthService.java around lines
171 - 178, The MongoDB health check may NPE by unboxing a null from
pingResult.getDouble("ok") and uses fragile equality; update the lambda in
performHealthCheck to first verify pingResult is non-null and contains the "ok"
key, retrieve the value as a Number (e.g., Number okVal = (Number)
pingResult.get("ok")) or via getDouble with null-check, ensure okVal != null,
then use Double.compare(okVal.doubleValue(), 1.0) == 0 or a tolerance (e.g., >=
0.999) to decide success; if the key is missing or the value indicates failure
return new HealthCheckResult(false, null, "Ping returned unexpected or missing
ok value") and keep getMongoDBVersion() and HealthCheckResult usage unchanged.

biological-screening-device-url=http://localhost:8096/ezdx-hub-connect-srv

## MongoDB Configuration
spring.data.mongodb.host=mongodb-container
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These don't belong here. It's environment related variables.

submodules: true
fetch-depth: 0

- name: Fetch base branch
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is this change about?

@drtechie
Copy link
Member

Admin-API doesn't talk to Mongo directly. This is a dependency for FHIR-API.
We can skip the check. Some deployments run without Mongo. They are going to show false negative health.

@Suraj-kumar00 can you also show the final JSON output?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants