Skip to content

[Improve] add connection check when get connection #10

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 15 commits into
base: master
Choose a base branch
from

Conversation

arvi18
Copy link

@arvi18 arvi18 commented Jul 30, 2025

What's changed?

Checklist

  • I have read the Contributing Guide
  • I have written the necessary doc or comment.
  • I have added the necessary unit tests and all cases have passed.

Add or update API

  • I have added the necessary e2e tests and all cases have passed.

Summary by CodeRabbit

  • New Features

    • Added automatic connection validation for database, SSH, JMX, Redfish, and Redis connections to ensure only active connections are used.
  • Bug Fixes

    • Improved error handling when retrieving cached connections, returning null if the connection is invalid or closed.
  • Tests

    • Updated tests to accommodate the new connection validation mechanism.

Copy link

coderabbitai bot commented Jul 30, 2025

Walkthrough

A new check() method was introduced as an abstract method in the AbstractConnection class, requiring all concrete connection classes (JDBC, JMX, MongoDB, Redfish, Redis, SSH) to implement connection validation logic. The getConnection() methods in these classes now invoke check() before returning a connection, ensuring only valid connections are handed out. Related error handling and logging were updated accordingly. Associated test code was adapted to implement the new abstract method.

Changes

Cohort / File(s) Change Summary
AbstractConnection Refactor
collector/.../cache/AbstractConnection.java
Removed Lombok @Slf4j, added abstract check() method, updated close() to use this.closeConnection().
JDBC Connection Validation
collector/.../cache/JdbcConnect.java
Added check() method to validate JDBC connection; getConnection() now calls check() and returns null on failure, with error logging.
JMX Connection Validation
collector/.../cache/JmxConnect.java
Added check() method to validate JMX connection; getConnection() now calls check() and returns null on failure, with error logging.
MongoDB Connection Validation
collector/.../cache/MongodbConnect.java
Added check() method that pings MongoDB; getConnection() now calls check() and returns null on failure, with error logging.
Redfish Connection Validation
collector/.../cache/RedfishConnect.java
Added check() method to validate Redfish session; getConnection() now calls check() and returns null on failure, with error logging.
Redis Connection Validation
collector/.../cache/RedisConnect.java
Added check() method to validate Redis connection; getConnection() now calls check() and returns null on failure, with error logging.
SSH Connection Validation
collector/.../cache/SshConnect.java
Added check() method to validate SSH session; getConnection() now calls check() and returns null on failure, with error logging.
Redis Connection Handling Refactor
collector/.../redis/RedisCommonCollectImpl.java
Refactored method for retrieving Redis connections to use new validation logic, simplified error handling, and updated cache cleanup on invalid connections.
Test Adaptation
collector/.../cache/CommonCacheTest.java
Implemented empty check() method in the anonymous test subclass of AbstractConnection to satisfy new abstract method requirement.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Cache
    participant Connection

    Client->>Cache: request getConnection()
    Cache->>Connection: check()
    alt check() succeeds
        Cache->>Client: return connection
    else check() fails (throws)
        Cache->>Client: return null (log error)
        Cache->>Connection: closeConnection() (async, if applicable)
        Cache->>Cache: remove cache entry
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~15–20 minutes

Poem

A rabbit hops through code so bright,
Connections checked before they bite,
No more stale or broken ties,
Each handshake now is truly wise.
From JDBC to Redis streams,
Only healthy links—no broken dreams!
🐇✨

Note

⚡️ Unit Test Generation is now available in beta!

Learn more here, or try it out under "Finishing Touches" below.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch clone-0722-yuluo/optimize-collector

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Summary of Changes

Hello @arvi18, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request enhances the robustness of connection management across various data sources by introducing a standardized mechanism to verify connection validity before use. It refactors existing connection classes to incorporate a new check() method, ensuring that stale or closed connections are identified and handled proactively, thereby improving the reliability of data collection.

Highlights

  • Standardized Connection Health Check: Introduced an abstract check() method in AbstractConnection.java to define a common interface for verifying the health of a connection before it is used.
  • Concrete Connection Implementations: Implemented the new check() method in various concrete connection classes (JdbcConnect, JmxConnect, MongodbConnect, RedfishConnect, RedisConnect, SshConnect), each with specific logic tailored to its connection type (e.g., isClosed(), ping command, isOpen()).
  • Proactive Connection Validation: Modified the getConnection() method in all affected concrete connection classes to call the new check() method. If the check fails, an error is logged, and null is returned, preventing the use of invalid or stale connections.
  • Refactored Redis Connection Handling: Updated RedisCommonCollectImpl.java to leverage the new check() mechanism when retrieving Redis connections from the cache, improving the handling of invalid cached connections by attempting to close and remove them upon detection.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point in your pull request via creating an issue comment (i.e. comment on the pull request page) using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in issue comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments or fill out our survey to provide feedback.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

refacto-test bot commented Jul 30, 2025

🤖 Refacto.AI: PR Summary & Reviewer Guide

🎯 1. The Goal (Why was this PR raised?)

This PR aims to improve connection handling by adding connection validation checks when retrieving connections from cache. The implementation adds a new check() method to the connection abstraction and implements this method in all connection type implementations.

🗺️ 2. The Changes (What was implemented?)

File Name Implementation Details Goal / Requirement Addressed
collector/src/main/java/org/apache/hertzbeat/collector/collect/common/cache/AbstractConnection.java (Modified) - Removed @Slf4j annotation
- Added abstract check() method to validate connection status
- Updated close() method to use this.closeConnection()
Add connection validation capability
collector/src/main/java/org/apache/hertzbeat/collector/collect/common/cache/JdbcConnect.java (Modified) - Implemented check() method to verify if connection is closed
- Updated getConnection() to call check() before returning the connection
- Added error handling to return null if connection check fails
Implement connection validation for JDBC
collector/src/main/java/org/apache/hertzbeat/collector/collect/common/cache/JmxConnect.java (Modified) - Implemented check() method to verify connection ID is not empty
- Updated getConnection() to call check() before returning the connection
- Added error handling to return null if connection check fails
Implement connection validation for JMX
collector/src/main/java/org/apache/hertzbeat/collector/collect/common/cache/MongodbConnect.java (Modified) - Added import for Document class
- Implemented check() method using ping command to verify connection
- Updated getConnection() to call check() before returning the connection
- Added error handling to return null if connection check fails
Implement connection validation for MongoDB
collector/src/main/java/org/apache/hertzbeat/collector/collect/common/cache/RedfishConnect.java (Modified) - Implemented check() method to verify connection is open
- Updated getConnection() to call check() before returning the connection
- Added error handling to return null if connection check fails
Implement connection validation for Redfish
collector/src/main/java/org/apache/hertzbeat/collector/collect/common/cache/RedisConnect.java (Modified) - Implemented check() method to verify connection is open
- Updated getConnection() to call check() before returning the connection
- Added error handling to return null if connection check fails
Implement connection validation for Redis
collector/src/main/java/org/apache/hertzbeat/collector/collect/common/cache/SshConnect.java (Modified) - Implemented check() method to verify SSH session is open
- Updated getConnection() to call check() before returning the connection
- Added error handling to return null if connection check fails
Implement connection validation for SSH
collector/src/main/java/org/apache/hertzbeat/collector/collect/redis/RedisCommonCollectImpl.java (Modified) - Refactored getStatefulConnection() method to use the new connection validation
- Simplified connection handling logic
- Improved error handling and logging
Use new connection validation in Redis collector
collector/src/test/java/org/apache/hertzbeat/collector/collect/common/cache/CommonCacheTest.java (Modified) - Added implementation for the new check() method in test class Update test to support new connection validation

🤔 3. Key Areas for Human Review

Area of Concern: Connection Handling Logic

  • File: collector/src/main/java/org/apache/hertzbeat/collector/collect/redis/RedisCommonCollectImpl.java (Lines 236-259)
  • Why: This file contains significant refactoring of the connection handling logic, which is critical for proper Redis data collection. The changes modify how connections are validated and error handling flow.
  • Testing Instruction: Test Redis monitoring with both valid and invalid connections to ensure the system properly handles connection failures and doesn't cause unexpected errors or memory leaks.

Area of Concern: Connection Validation Implementation

  • File: All connection implementation files (JdbcConnect.java, JmxConnect.java, MongodbConnect.java, etc.)
  • Why: Each connection type implements the validation differently based on its specific technology. An incorrect implementation could cause false positives/negatives in connection validation.
  • Testing Instruction: Test each connection type (JDBC, JMX, MongoDB, Redfish, Redis, SSH) with both working and non-working connections to verify that the validation correctly identifies connection status.

Area of Concern: Error Handling in Connection Classes

  • File: All connection implementation files
  • Why: All implementations now return null when connection validation fails, which could lead to NullPointerExceptions if callers don't handle this case properly.
  • Testing Instruction: Review all code that uses these connection classes to ensure they properly handle null return values. Test scenarios where connections fail to verify the application gracefully handles these failures.

Copy link

refacto-test bot commented Jul 30, 2025

Refacto is reviewing this PR. Please wait for the review comments to be posted.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a connection check when retrieving a connection from the cache for various protocols (JDBC, JMX, MongoDB, Redfish, Redis, SSH). The goal is to ensure that clients receive a valid, open connection.

The overall approach is good, but there are several areas for improvement:

  • A critical logic error in RedisCommonCollectImpl prevents invalid connections from being removed from the cache.
  • Exception logging is insufficient across all new connection wrapper classes, which will make debugging harder.
  • The connection check for JMX is unreliable.
  • There are also some minor code style and naming issues.

I've provided detailed comments and suggestions to address these points.

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: 4

🔭 Outside diff range comments (1)
collector/src/main/java/org/apache/hertzbeat/collector/collect/common/cache/RedfishConnect.java (1)

1-62: Standardize exception handling in check() methods

There’s inconsistent use of checked vs. unchecked exceptions across your AbstractConnection subclasses. To improve maintainability and clarity, please choose a single strategy (e.g. all methods throw a checked Exception or a custom ConnectionException, or make them all unchecked) and apply it uniformly.

Files requiring updates:

  • collector/src/main/java/org/apache/hertzbeat/collector/collect/common/cache/SshConnect.java
    • currently throws and declares generic Exception—OK if you choose checked, otherwise adjust.
  • collector/src/main/java/org/apache/hertzbeat/collector/collect/common/cache/RedisConnect.java
    • declares throws Exception but uses throw new RuntimeException(...).
  • collector/src/main/java/org/apache/hertzbeat/collector/collect/common/cache/RedfishConnect.java
    • same mismatch (throws Exception vs. RuntimeException).
  • collector/src/main/java/org/apache/hertzbeat/collector/collect/common/cache/JmxConnect.java
    • same mismatch.
  • collector/src/main/java/org/apache/hertzbeat/collector/collect/common/cache/JdbcConnect.java
    • narrows signature to throws SQLException. Decide whether to align on generic Exception or a shared custom exception.
  • collector/src/main/java/org/apache/hertzbeat/collector/collect/common/cache/MongodbConnect.java
    • currently relies on driver’s unchecked exceptions—consider making its exception behavior explicit.

Suggested paths forward:

  • If you stick with the existing throws Exception in the abstract base, change all subclasses to throw new Exception("…") (or a custom checked exception) instead of RuntimeException.
  • Alternatively, introduce a ConnectionException extends Exception (or RuntimeException) and have every check() throw it, updating both signature and throw sites.
  • If you prefer unchecked errors, update the abstract method to remove throws Exception and let subclasses consistently throw RuntimeException or your custom unchecked type.

Please update the above files to reflect your chosen approach.

🧹 Nitpick comments (5)
collector/src/main/java/org/apache/hertzbeat/collector/collect/common/cache/SshConnect.java (1)

49-59: Good error handling pattern with minor suggestion.

The error handling approach is solid - calling check() before returning the connection and gracefully handling failures by logging and returning null. This prevents invalid connections from being used downstream.

Consider being more specific about the exception type in the error message:

 catch (Exception e) {
-    log.error(e.getMessage());
+    log.error("SSH connection validation failed: {}", e.getMessage());
     return null;
 }
collector/src/main/java/org/apache/hertzbeat/collector/collect/common/cache/JdbcConnect.java (1)

54-60: Improve error logging to include stack trace.

The current logging only captures the exception message, which may not provide sufficient debugging information. Consider logging the full exception.

 try {
     this.check();
 }
 catch (SQLException e) {
-    log.error(e.getMessage());
+    log.error("JDBC connection check failed: {}", e.getMessage(), e);
     return null;
 }
collector/src/main/java/org/apache/hertzbeat/collector/collect/common/cache/JmxConnect.java (1)

54-60: Improve error logging consistency.

The error message format should be consistent with other connection classes and include more context.

 try {
     this.check();
 }
 catch (Exception e) {
-    log.error(e.getMessage());
+    log.error("JMX connection check failed: {}", e.getMessage(), e);
     return null;
 }
collector/src/main/java/org/apache/hertzbeat/collector/collect/common/cache/MongodbConnect.java (1)

42-46: Consider alternative database for ping command.

Using the "admin" database for the ping command may fail if the MongoDB user doesn't have access to the admin database. Consider using a more accessible approach.

Consider using the default database or a more permissive approach:

 @Override
 public void check() throws Exception {
-    mongoClient.getDatabase("admin").runCommand(new Document("ping", 1));
+    // Try to get database names as a connectivity check, which typically requires fewer permissions
+    mongoClient.listDatabaseNames().first();
 }

Alternatively, you could catch permission-related exceptions and try a fallback approach.

collector/src/main/java/org/apache/hertzbeat/collector/collect/redis/RedisCommonCollectImpl.java (1)

248-248: Consider using structured logging for better observability.

The current logging is informative but could benefit from structured logging to make it easier to monitor connection health issues.

-log.info("The Redis connection from cache is invalid, closing and removing: {}", e.getMessage());
+log.warn("Redis connection validation failed, cleaning up cached connection. Identifier: {}, Error: {}", 
+         identifier, e.getMessage(), e);
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b02837b and 53ffca0.

📒 Files selected for processing (9)
  • collector/src/main/java/org/apache/hertzbeat/collector/collect/common/cache/AbstractConnection.java (2 hunks)
  • collector/src/main/java/org/apache/hertzbeat/collector/collect/common/cache/JdbcConnect.java (2 hunks)
  • collector/src/main/java/org/apache/hertzbeat/collector/collect/common/cache/JmxConnect.java (1 hunks)
  • collector/src/main/java/org/apache/hertzbeat/collector/collect/common/cache/MongodbConnect.java (2 hunks)
  • collector/src/main/java/org/apache/hertzbeat/collector/collect/common/cache/RedfishConnect.java (1 hunks)
  • collector/src/main/java/org/apache/hertzbeat/collector/collect/common/cache/RedisConnect.java (1 hunks)
  • collector/src/main/java/org/apache/hertzbeat/collector/collect/common/cache/SshConnect.java (1 hunks)
  • collector/src/main/java/org/apache/hertzbeat/collector/collect/redis/RedisCommonCollectImpl.java (1 hunks)
  • collector/src/test/java/org/apache/hertzbeat/collector/collect/common/cache/CommonCacheTest.java (1 hunks)
🔇 Additional comments (8)
collector/src/main/java/org/apache/hertzbeat/collector/collect/common/cache/AbstractConnection.java (2)

36-39: LGTM! Well-designed abstract contract for connection validation.

The introduction of the abstract check() method establishes a consistent contract for connection validation across all subclasses. The method signature appropriately throws Exception to allow flexibility in implementation-specific error handling.


44-44: Good improvement in method clarity.

Making the call to this.closeConnection() explicit improves code readability and makes the delegation pattern more obvious.

collector/src/test/java/org/apache/hertzbeat/collector/collect/common/cache/CommonCacheTest.java (1)

49-51: LGTM! Appropriate test adaptation for the new abstract method.

The empty implementation of check() is suitable for the mock connection used in cache testing, as the focus is on testing cache behavior rather than connection validation logic.

collector/src/main/java/org/apache/hertzbeat/collector/collect/common/cache/SshConnect.java (1)

41-47: LGTM! Clear and appropriate connection validation.

The implementation correctly checks if the SSH session is open and provides a descriptive error message. The validation logic is straightforward and appropriate for SSH connections.

collector/src/main/java/org/apache/hertzbeat/collector/collect/common/cache/RedisConnect.java (1)

50-61: LGTM! Consistent error handling pattern.

The error handling approach matches the pattern established in other connection classes - validating before returning and gracefully handling failures with logging.

collector/src/main/java/org/apache/hertzbeat/collector/collect/common/cache/RedfishConnect.java (1)

49-61: LGTM! Consistent error handling pattern.

The implementation follows the established pattern of validating connections before returning them and handling failures gracefully with appropriate logging.

collector/src/main/java/org/apache/hertzbeat/collector/collect/common/cache/MongodbConnect.java (1)

51-57: LGTM - Consistent error handling implementation.

The error handling pattern is consistent with other connection classes and properly logs errors before returning null.

collector/src/main/java/org/apache/hertzbeat/collector/collect/redis/RedisCommonCollectImpl.java (1)

245-256: Excellent error handling and cleanup logic.

The refactored connection retrieval properly handles invalid connections by:

  1. Catching RuntimeException from the new check() mechanism
  2. Attempting to close the connection asynchronously
  3. Removing the invalid connection from cache
  4. Providing informative logging

This prevents accumulation of invalid connections and ensures proper resource cleanup.

@coderabbit-test coderabbit-test deleted a comment from refacto-test bot Jul 30, 2025
@coderabbit-test coderabbit-test deleted a comment from refacto-test bot Jul 30, 2025
@coderabbit-test coderabbit-test deleted a comment from refacto-test bot Jul 30, 2025
@coderabbit-test coderabbit-test deleted a comment from refacto-test bot Jul 30, 2025
Copy link

refacto-test bot commented Jul 30, 2025

Solid Foundation - Critical Connection Validation Improvements Needed!

Review Summary

This PR introduces an important connection validation mechanism through the new check() method in AbstractConnection and implements it across all connection types. This is a valuable reliability improvement that will help prevent usage of invalid connections. However, our analysis identified a critical issue with the error handling approach - returning null on validation failure instead of throwing exceptions will lead to NullPointerExceptions and system instability. With a few targeted fixes to the error handling strategy, this will be an excellent enhancement to the connection management system.

Well Done!!!

  • Excellent implementation of connection validation checks across multiple connection types with appropriate validation logic for each type
  • Consistent implementation pattern across all connection classes following good object-oriented design principles
  • Good abstraction with the new abstract method in the base class that enforces implementation across all subclasses
  • Proper logging of error messages when connections are invalid, providing useful diagnostic information

Files Processed

collector/src/main/java/org/apache/hertzbeat/collector/collect/common/cache/AbstractConnection.java 17-48
collector/src/main/java/org/apache/hertzbeat/collector/collect/common/cache/JdbcConnect.java 40-60
collector/src/main/java/org/apache/hertzbeat/collector/collect/common/cache/JmxConnect.java 40-64
collector/src/main/java/org/apache/hertzbeat/collector/collect/common/cache/MongodbConnect.java 19-60
collector/src/main/java/org/apache/hertzbeat/collector/collect/common/cache/RedfishConnect.java 38-62
collector/src/main/java/org/apache/hertzbeat/collector/collect/common/cache/RedisConnect.java 39-63
collector/src/main/java/org/apache/hertzbeat/collector/collect/common/cache/SshConnect.java 38-60
collector/src/main/java/org/apache/hertzbeat/collector/collect/redis/RedisCommonCollectImpl.java 236-260
collector/src/test/java/org/apache/hertzbeat/collector/collect/common/cache/CommonCacheTest.java 45-53

📌 Additional Comments (2)

Reliability

Consider Adding Null Checks in Other Connection Implementations

Explanation: Similar to the JmxConnect issue, other connection implementations like RedisConnect, RedfishConnect, and SshConnect don't check if the connection is null before accessing its methods. While the main issue is addressed in the actionable finding for JmxConnect, it would be good practice to add similar null checks in all implementations for consistency and robustness.

@Override
 public void check() throws Exception {

 if (!connection.isOpen()) {
 throw new RuntimeException("Connection is closed");

Fix Suggestion: Add null checks in all connection check() implementations.

+  if (connection == null) {
+  throw new RuntimeException("Connection is null");
+  }
+  if (!connection.isOpen()) {
+  throw new RuntimeException("Connection is closed");
Rationale
  • Ensures consistent null checking across all connection implementations
  • Prevents potential NullPointerExceptions in edge cases
  • Improves error messages by distinguishing between null and closed connections
  • Follows defensive programming best practices
References
  • Standard: Defensive Programming - Null Safety
---

Maintainability

Inconsistent Error Handling in Connection Validation

Explanation: The abstract class defines a new check() method that implementations must provide, but it lacks a standard error handling strategy. Each implementation returns null when connection validation fails, which can lead to NullPointerExceptions later in the code. This inconsistent approach to error handling violates the Liskov Substitution Principle, as callers cannot reliably predict the behavior of getConnection() across different implementations.

package org.apache.hertzbeat.collector.collect.common.cache;

/**
 * AbstractConnection
 _/

public abstract class AbstractConnection<T> implements AutoCloseable {

Fix Suggestion: Improve documentation for check() method to standardize implementation expectations

+  /**
+  * Check connection validity when getting a connection.
+  * Implementations should verify that the connection is still valid and usable.
+  * If the connection is invalid, implementations should throw an appropriate exception.
+  *
+  * @throws Exception if the connection is invalid or unusable
+  */
+  public abstract void check() throws Exception;
Rationale
  • Provides clear documentation about the expected behavior of the check() method
  • Establishes a consistent contract for all implementations to follow
  • Improves maintainability by making the error handling expectations explicit
  • Helps future developers understand the purpose and usage of the method
References
  • Standard: SOLID Principles - Liskov Substitution Principle, Clean Code - Error Handling
---

Comment on lines 40 to +60
}
}

@Override
public void check() throws SQLException {

if (connection.isClosed()) {
throw new SQLException("Connection is closed");
}
}

@Override
public Connection getConnection() {

try {
this.check();
}
catch (SQLException e) {
log.error(e.getMessage());
return null;
}
Copy link

Choose a reason for hiding this comment

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

Returning null instead of throwing exceptions on connection validation failures

The getConnection() method silently returns null when connection validation fails instead of propagating the exception. This violates the fail-fast principle and will lead to NullPointerExceptions when client code attempts to use the connection. Since the method signature doesn't indicate that null can be returned, callers are unlikely to check for null values, resulting in runtime failures that are difficult to diagnose and potentially causing system instability.

Suggested change
}
}
@Override
public void check() throws SQLException {
if (connection.isClosed()) {
throw new SQLException("Connection is closed");
}
}
@Override
public Connection getConnection() {
try {
this.check();
}
catch (SQLException e) {
log.error(e.getMessage());
return null;
}
@Override
public Connection getConnection() {
try {
this.check();
return connection;
}
catch (SQLException e) {
log.error("Connection validation failed", e);
throw new RuntimeException("Failed to get valid JDBC connection", e);
}
}

Comment on lines +43 to +47
@Override
public void check() throws Exception {

if (connection.getConnectionId().isEmpty()) {
throw new RuntimeException("connection is closed");
Copy link

Choose a reason for hiding this comment

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

Potential NullPointerException in JmxConnect.check()

The JmxConnect.check() method doesn't handle the case where the connection itself might be null. If the connection object is null (which could happen if connection initialization failed), calling connection.getConnectionId() will throw a NullPointerException. This would bypass the intended error handling in the getConnection() method.

Suggested change
@Override
public void check() throws Exception {
if (connection.getConnectionId().isEmpty()) {
throw new RuntimeException("connection is closed");
if (connection == null || connection.getConnectionId().isEmpty()) {
throw new RuntimeException("connection is null or closed");

Comment on lines 236 to 260
* @return connection
*/
private StatefulConnection<String, String> getStatefulConnection(CacheIdentifier identifier) {
StatefulConnection<String, String> connection = null;

Optional<RedisConnect> cacheOption = connectionCommonCache.getCache(identifier, true);

if (cacheOption.isPresent()) {
RedisConnect redisConnect = cacheOption.get();
connection = redisConnect.getConnection();
if (!connection.isOpen()) {

try {
return redisConnect.getConnection();
} catch (RuntimeException e) {
log.info("The Redis connection from cache is invalid, closing and removing: {}", e.getMessage());
try {
connection.closeAsync();
} catch (Exception e) {
log.info("The redis connect form cache, close error: {}", e.getMessage());
redisConnect.getConnection().closeAsync();
} catch (Exception closeException) {
log.info("Error closing Redis connection: {}", closeException.getMessage());
}
connection = null;
connectionCommonCache.removeCache(identifier);
}
}
return connection;

return null;
}

Copy link

Choose a reason for hiding this comment

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

Inefficient Redis Connection Management in RedisCommonCollectImpl

The getStatefulConnection method has been updated to use the new check() functionality, but it makes a second call to getConnection() when closing an invalid connection. This creates a performance inefficiency as it could trigger another validation check and potentially another exception. Additionally, it logs connection issues at INFO level instead of ERROR or WARN, which could hide important connection problems in production environments.

Suggested change
* @return connection
*/
private StatefulConnection<String, String> getStatefulConnection(CacheIdentifier identifier) {
StatefulConnection<String, String> connection = null;
Optional<RedisConnect> cacheOption = connectionCommonCache.getCache(identifier, true);
if (cacheOption.isPresent()) {
RedisConnect redisConnect = cacheOption.get();
connection = redisConnect.getConnection();
if (!connection.isOpen()) {
try {
return redisConnect.getConnection();
} catch (RuntimeException e) {
log.info("The Redis connection from cache is invalid, closing and removing: {}", e.getMessage());
try {
connection.closeAsync();
} catch (Exception e) {
log.info("The redis connect form cache, close error: {}", e.getMessage());
redisConnect.getConnection().closeAsync();
} catch (Exception closeException) {
log.info("Error closing Redis connection: {}", closeException.getMessage());
}
connection = null;
connectionCommonCache.removeCache(identifier);
}
}
return connection;
return null;
}
private StatefulConnection<String, String> getStatefulConnection(CacheIdentifier identifier) {
Optional<RedisConnect> cacheOption = connectionCommonCache.getCache(identifier, true);
if (cacheOption.isPresent()) {
RedisConnect redisConnect = cacheOption.get();
StatefulConnection<String, String> connection = null;
try {
connection = redisConnect.getConnection();
return connection;
} catch (RuntimeException e) {
log.warn("The Redis connection from cache is invalid, removing: {}", e.getMessage());
try {
if (connection != null) {
connection.closeAsync();
}
} catch (Exception closeException) {
log.warn("Error closing Redis connection: {}", closeException.getMessage());
}
connectionCommonCache.removeCache(identifier);
}
}
return null;

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.

3 participants