Skip to content

Implement a closeAll utility to close multiple closeables #3470

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 4 commits into
base: main
Choose a base branch
from

Conversation

ohadzeliger
Copy link
Contributor

Tech debt from the ThrottlingIterator work. Close multiple closeables and capture all exceptions.
Resolve #3465

@ohadzeliger ohadzeliger self-assigned this Jul 7, 2025
@ohadzeliger ohadzeliger added the enhancement New feature or request label Jul 7, 2025
@ohadzeliger ohadzeliger requested a review from ScottDugas July 7, 2025 19:42
@ohadzeliger ohadzeliger marked this pull request as ready for review July 7, 2025 19:52
*/
@SuppressWarnings("PMD.CloseResource")
public static void closeAll(AutoCloseable... closeables) throws CloseException {
CloseException accumulatedException = null;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why create a new exception type to accumulate, rather than setting it to the first exception thrown?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That was how I initially tried to implement this but the compiler complained about "close() method can throw InterruptedException" when the close() declares to throw Exception.
Similar to the issue described here: TritonDataCenter/java-manta#322

if (logger.isWarnEnabled()) {
logger.warn("Failed to close the throttled iterator", e);
}
// Do not rethrow. We are trying to close the runner and the exception should log all errors
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why the change here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I thought this would be a better fit to a usage like:

    RepairValidationResults repairResults;
    try (RecordRepairValidateRunner repairRunner = builder.buildRepairRunner(false)) {
        repairResults = repairRunner.run().join();
    }
    // Handle results

Where a failure to close would disrupt the flow and cause the loss of already collected results.
But I am not too strongly opinionated about this.

Copy link
Collaborator

Choose a reason for hiding this comment

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

This seems only tangentially related to the purpose of the PR.

Also, I'm not sure I agree, I think you would want to do:

RepairValidationResults repairResults;
    try (RecordRepairValidateRunner repairRunner = builder.buildRepairRunner(false)) {
        repairResults = repairRunner.run().join();
        // handle results
    }

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Reverted to previous behavior. Also, since CloseException is now declared on the signature of the method, I moved the exception to its own top level class.

}

/**
* Exception thrown when the {@link CloseableUtils#closeAll} method catches an exception.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
* Exception thrown when the {@link CloseableUtils#closeAll} method catches an exception.
* Exception thrown when the {@link #closeAll} method catches an exception.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Exception moved to separate file.


package com.apple.foundationdb.util;

public class CloseableUtils {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Javadoc would be good, something short and sweet, like

Suggested change
public class CloseableUtils {
/**
* Utility methods to help interact with {@link AutoCloseable} things.
**/
public class CloseableUtils {

Copy link
Collaborator

Choose a reason for hiding this comment

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

Also, an API annotation. INTERNAL I think.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done x2

if (logger.isWarnEnabled()) {
logger.warn("Failed to close the throttled iterator", e);
}
// Do not rethrow. We are trying to close the runner and the exception should log all errors
Copy link
Collaborator

Choose a reason for hiding this comment

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

This seems only tangentially related to the purpose of the PR.

Also, I'm not sure I agree, I think you would want to do:

RepairValidationResults repairResults;
    try (RecordRepairValidateRunner repairRunner = builder.buildRepairRunner(false)) {
        repairResults = repairRunner.run().join();
        // handle results
    }

for (AutoCloseable closeable: closeables) {
try {
closeable.close();
} catch (Exception e) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Since you are catch a generic exception, you are supposed to re-interrupt the current thread.

Also, probably worth a comment in the code here similar to the one on the PR explaining why we are converting it to a CloseException

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done. I think there could be no case of InterruptedException thrown from a close(), but it doesn't hurt to add a catch block.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Need a utility to close multiple AutoCloseabless
2 participants