emecii commented on code in PR #944:
URL: https://github.com/apache/flink-agents/pull/944#discussion_r3742785700


##########
runtime/src/main/java/org/apache/flink/agents/runtime/operator/PythonBridgeManager.java:
##########
@@ -291,14 +294,11 @@ boolean isInitialized() {
 
     @Override
     public void close() throws Exception {
-        if (pythonActionExecutor != null) {
-            pythonActionExecutor.close();
-        }
-        if (pythonInterpreter != null) {
-            pythonInterpreter.close();
-        }
-        if (pythonEnvironmentManager != null) {
-            pythonEnvironmentManager.close();
-        }
+        IOUtils.closeAll(

Review Comment:
   Following up on @weiqingy's note in #987 that these two PRs disagree on 
mechanism rather than merely touching the same seven files. I'm the author of 
#987, so flagging my own interest up front.
   
   I checked the `Error` case empirically against `flink-core-2.3.0` rather 
than reading the source, and the concern holds. Three closeables that record 
whether `close()` ran, the first one throwing:
   
   ```
   A (first throws OutOfMemoryError):   thrown=java.lang.OutOfMemoryError: boom
   A closed flags -> a1=true a2=false a3=false
   B (first throws IllegalStateException): 
thrown=java.lang.IllegalStateException: boom
   B closed flags -> b1=true b2=true b3=true
   ```
   
   The varargs overload delegates to `closeAll(Iterable)`, which delegates to 
`closeAll(Iterable, Class<T>)` with `suppressedException = Exception.class`; 
that method rethrows anything not assignable to it *before* closing the rest. 
So `closeAll` continues past an `Exception` but stops dead on any 
non-`Exception` `Throwable`.
   
   At this call site that means an `Error` out of `longTermMemory.close()` or 
`pythonActionExecutor.close()` leaves `pythonInterpreter` and 
`pythonEnvironmentManager` unclosed — the native Python state this PR exists to 
release, retained for the lifetime of the TaskManager JVM. The same shape 
appears at the other two sites:
   
   - `ActionExecutionOperator.close()`: an `Error` from `resourceCache` skips 
`contextManager`, `pythonBridge`, `eventRouter`, `durableExecManager`, and the 
trailing `super::close`, so `stateHandler.dispose()` is skipped too.
   - `ActionTaskContextManager.close()`: an `Error` from the runner context 
strands the continuation executor's thread pool.
   
   Worth noting that `ResourceCache.close()` (`ResourceCache.java:148` and 
`:160`) currently catches only `Exception`, so an `Error` out of a cached 
`Resource.close()` propagates unchanged and is a concrete way to reach the 
first of those.
   
   Would you consider replacing `closeAll` with a `catch (Throwable)` ladder 
that aggregates via `ExceptionUtils.firstOrSuppressed` and rethrows via 
`ExceptionUtils.rethrowException`? It keeps the same 
first-failure-wins-with-later-ones-suppressed semantics, and `rethrowException` 
passes both `Error` and `Exception` through unwrapped, so callers still see the 
original type and instance. That is the shape `KafkaActionStateStore.close()` 
(#948) and `ResourceCache.close()` already use in this module.
   
   On sequencing, since we overlap on seven files: #987 is the smaller change 
and only rewrites the three `close()` methods. If it lands first, this PR's 
rebase becomes additive — `longTermMemory` and `pythonResourceAdapter` slot 
into ladders that already exist — instead of a mechanism swap in one direction 
or the other. I'm equally happy to go the other way and rework #987 as a 
follow-up on top of this if you'd prefer not to reshuffle. Mainly I'd like the 
two not to land opposite decisions on the `Error` case. What works best for you?
   



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