wenjin272 commented on code in PR #987:
URL: https://github.com/apache/flink-agents/pull/987#discussion_r3793676469


##########
runtime/src/main/java/org/apache/flink/agents/runtime/python/utils/PythonActionExecutor.java:
##########
@@ -201,6 +201,7 @@ public boolean callPythonAwaitable(String 
pythonAwaitableRef) {
         return (boolean) ((Object[]) invokeResult)[0];
     }
 
+    @Override

Review Comment:
   [P1] `PythonActionExecutor.close()` can still skip the second cleanup step. 
If `interpreter.invoke(CLOSE_ASYNC_THREAD_POOL)` throws, 
`CLOSE_FLINK_RUNNER_CONTEXT` is never invoked. `PythonBridgeManager` then 
continues closing the interpreter, so the runner context's LTM and resource 
cache are not explicitly closed first. I reproduced this with a mocked 
interpreter: after the first `invoke()` throws, the second invocation is not 
made. Could this method use the same first-failure/suppressed-failure ladder 
and add a regression test?



##########
runtime/src/main/java/org/apache/flink/agents/runtime/ResourceCache.java:
##########
@@ -140,32 +141,32 @@ public void put(String name, ResourceType type, Resource 
resource) {
 
     @Override
     public void close() throws Exception {
-        Exception firstException = null;
+        // Close every cached resource, then the resource context, even when 
an earlier close
+        // fails. The first failure is rethrown with the later ones suppressed.
+        //
+        // The ladders catch Throwable, not Exception: 
ActionExecutionOperator.close() closes this
+        // cache before the Python interpreter because cached resources may 
hold Python references,
+        // so a non-Exception Throwable escaping here would leave the 
remaining resources open
+        // while the interpreter behind them is torn down anyway. 
ExceptionUtils.rethrowException
+        // passes Error and Exception through unchanged, so the caller still 
sees the original.
+        Throwable firstFailure = null;
         for (Map<String, Resource> resources : cache.values()) {
             for (Resource resource : resources.values()) {
                 try {
                     resource.close();
-                } catch (Exception e) {
-                    if (firstException == null) {
-                        firstException = e;
-                    } else {
-                        firstException.addSuppressed(e);
-                    }
+                } catch (Throwable t) {
+                    firstFailure = ExceptionUtils.firstOrSuppressed(t, 
firstFailure);
                 }
             }
         }
         cache.clear();
         try {
             resourceContext.close();
-        } catch (Exception e) {
-            if (firstException == null) {
-                firstException = e;
-            } else {
-                firstException.addSuppressed(e);
-            }
+        } catch (Throwable t) {
+            firstFailure = ExceptionUtils.firstOrSuppressed(t, firstFailure);

Review Comment:
   [P2] Catching `Throwable` here only aggregates failures after 
`ResourceContextImpl.close()` returns or throws, but its nested 
[`SkillManager.closeRepos()`](https://github.com/apache/flink-agents/blob/0c4df632101d1a059bb0cb6e1b35cf434cfb5181/runtime/src/main/java/org/apache/flink/agents/runtime/skill/SkillManager.java#L221-L242)
 still catches only `Exception`. If a repository's `close()` throws an `Error`, 
the remaining repositories are skipped; `ResourceContextImpl` then clears the 
manager reference in `finally`, so that cleanup cannot be retried. The new 
close-all guarantee therefore does not reach this nested branch. Could 
`SkillManager` use the same `Throwable` aggregation and get a regression test 
through the `ResourceCache`/`ResourceContext` path?



##########
runtime/src/main/java/org/apache/flink/agents/runtime/ResourceCache.java:
##########
@@ -140,32 +141,32 @@ public void put(String name, ResourceType type, Resource 
resource) {
 
     @Override
     public void close() throws Exception {
-        Exception firstException = null;
+        // Close every cached resource, then the resource context, even when 
an earlier close
+        // fails. The first failure is rethrown with the later ones suppressed.
+        //
+        // The ladders catch Throwable, not Exception: 
ActionExecutionOperator.close() closes this
+        // cache before the Python interpreter because cached resources may 
hold Python references,
+        // so a non-Exception Throwable escaping here would leave the 
remaining resources open
+        // while the interpreter behind them is torn down anyway. 
ExceptionUtils.rethrowException
+        // passes Error and Exception through unchanged, so the caller still 
sees the original.
+        Throwable firstFailure = null;
         for (Map<String, Resource> resources : cache.values()) {

Review Comment:
   [P2] The Java path now closes every resource after an earlier failure, but 
the equivalent [Python 
`ResourceCache.close()`](https://github.com/apache/flink-agents/blob/0c4df632101d1a059bb0cb6e1b35cf434cfb5181/python/flink_agents/runtime/resource_cache.py#L96-L108)
 is still sequential: the first resource failure skips the remaining resources, 
`_cache.clear()`, and `_resource_context.close()`. I reproduced 
`first_closed=True, second_closed=False, cache_size=1`. Could we align the 
Python lifecycle behavior and add the corresponding regression test?



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