hudi-agent commented on code in PR #19778:
URL: https://github.com/apache/hudi/pull/19778#discussion_r3904790420


##########
hudi-client/hudi-client-common/src/main/java/org/apache/hudi/client/BaseHoodieClient.java:
##########
@@ -142,19 +142,78 @@ private static TransactionManager 
buildTransactionManager(HoodieEngineContext co
     this.metrics = new HoodieMetrics(config, storage);
     this.txnManager = transactionManager;
     this.timeGenerator = timeGenerator;
-    startEmbeddedServerView();
-    runClientInitCallbacks();
+    try {
+      startEmbeddedServerView();
+      runClientInitCallbacks();
+    } catch (RuntimeException | Error e) {
+      // The constructor is not returning, so no caller ever gets an instance 
to close(): release here or leak.
+      releaseAfterFailedInit(e);

Review Comment:
   🤖 The guard here covers the base constructor's tail, so the 
bad-callback-class case is handled — nice. But the client is always a subclass, 
and the subclass work that runs after `super()` returns isn't covered: 
`BaseHoodieWriteClient`'s `createIndex(writeConfig)` / 
`emitIndexTypeMetrics(...)` and `SparkRDDWriteClient`'s `new 
SparkRDDTableServiceClient(...)` all execute once the base constructor has 
already started the embedded server, heartbeat, and txn-manager write lock. If 
any of those throw, the same resources leak exactly as before, since no 
instance escapes to call close(). Is closing that broader path in scope here, 
or intended as a follow-up?
   
   <sub><i>⚠️ AI-generated; verify before applying. React 👍/👎 to flag 
quality.</i></sub>



##########
hudi-client/hudi-client-common/src/main/java/org/apache/hudi/client/BaseHoodieWriteClient.java:
##########
@@ -1661,12 +1661,35 @@ public void releaseResources(String instantTime) {
 
   @Override
   public void close() {
-    // Stop timeline-server if running
-    super.close();
-    // Calling this here releases any resources used by your index, so make 
sure to finish any related operations
-    // before this point
-    this.index.close();
-    this.tableServiceClient.close();
+    // The index and the table service client are this class's own resources; 
a failure while the
+    // base client releases its own must not leave them open.
+    Exception failure = null;
+    try {
+      // Stop timeline-server if running
+      super.close();
+    } catch (Exception e) {
+      failure = e;
+    }
+    try {
+      // Calling this here releases any resources used by your index, so make 
sure to finish any related operations
+      // before this point
+      this.index.close();
+    } catch (Exception e) {
+      failure = failure == null ? e : addSuppressed(failure, e);
+    }
+    try {
+      this.tableServiceClient.close();
+    } catch (Exception e) {
+      failure = failure == null ? e : addSuppressed(failure, e);
+    }
+    if (failure != null) {
+      throw failure instanceof RuntimeException ? (RuntimeException) failure : 
new HoodieException(failure);
+    }
+  }

Review Comment:
   🤖 nit: the parent class calls this same helper `appendFailure` — could you 
use the same name here for consistency? `addSuppressed` also shadows 
`Throwable.addSuppressed`, which might cause a double-take. And since the 
parent's version handles `null` internally, the subclass's callers wouldn't 
need the inline `failure == null ? e :` guard if this were aligned.
   
   <sub><i>⚠️ AI-generated; verify before applying. React 👍/👎 to flag 
quality.</i></sub>



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to