joeyutong opened a new issue, #1057:
URL: https://github.com/apache/flink-agents/issues/1057

   > [!IMPORTANT]
   > **Draft.** Local A/B validation is complete. The draft marker is kept 
while the ownership scope and proposed abstraction are reviewed.
   
   ### Search before asking
   
   - [x] I searched in the 
[issues](https://github.com/apache/flink-agents/issues) and found nothing 
similar.
   
   ### Description
   
   Flink Agents invokes Python resources through Pemja in several runtime 
paths. Values crossing the Java/Python boundary may be represented by 
`PyObject` handles, and each such handle owns a native Python reference that 
must be released explicitly. Java garbage collection is not an ownership 
mechanism for these references.
   
   The current resource bridges do not apply one consistent ownership contract. 
Depending on the path, temporary arguments or return values can remain open, a 
value can outlive the bridge call without an explicit ownership transfer, or a 
partially initialized resource can be cached without rolling back its Python 
and native state. The affected paths include:
   
   - chat and embedding model setup/connections;
   - vector-store calls and returned document collections;
   - MCP servers, tools, prompts, and discovery;
   - Mem0 call-scoped values;
   - Python-backed `FunctionTool` calls;
   - Java and Python resource-cache initialization failures.
   
   Nested Python values are also relevant: closing only a top-level collection 
is insufficient when its elements are separate `PyObject` handles.
   
   The expected ownership contract is:
   
   1. one operation scope owns every temporary Python argument and result, 
including nested handles;
   2. values that intentionally outlive the operation are transferred to an 
explicit long-lived owner;
   3. results returned to ordinary Java callers are materialized into detached 
Java values before Python handles are released;
   4. resource creation and MCP discovery are transactional, so any failure 
closes all resources created before cache registration.
   
   This is related to, but distinct from, #942/#944 and #1048/#1049. Those 
pairs cover executor-lifetime handles across task restarts and per-Action 
handles respectively. This issue covers the remaining resource-bridge 
operations and partial-initialization paths.
   
   #### Independent local Flink A/B validation
   
   Six bounded jobs ran in a local Flink 2.2 session cluster. Every fixed and 
leak variant used a fresh TaskManager, one probe subtask, Pemja 0.5.7 in 
`MULTI_THREAD` mode, embedded CPython 3.11.15, 200 measured iterations, and 256 
KiB per tracked Python object.
   
   - Chat bridge: fixed `0` live messages/tools and `0` retained payload; leak 
variant retained `600` messages, `200` tool values, and `200 MiB`, with RSS 
increasing by `160.3 MiB`.
   - Vector bridge: fixed `0` live documents/normalized handles and `0` 
retained payload; leak variant retained `600` documents, `200` normalized 
handles, and about `100 MiB`, with RSS increasing by `99.1 MiB`.
   - Resource recreation: fixed `0` live resources and observed `200` logical 
close calls; leak variant retained `200` resources, made `0` logical close 
calls, and retained `50 MiB`.
   
   Exact live-reference counts, close counts, and reachable payload bytes are 
the primary evidence. RSS is supporting evidence because JVM/CPython startup 
and native allocator behavior can dominate a bounded run.
   
   ### How to reproduce
   
   1. Start a Flink job with one long-lived TaskManager and a Python-backed 
chat, vector, or resource bridge.
   2. Repeatedly invoke the bridge with non-trivial Python arguments/results, 
or repeatedly recreate a resource while keeping the TaskManager alive.
   3. Track affected Python objects with weak references and count logical 
close calls.
   4. Force Java and Python garbage collection after the measured operations.
   5. Compare the existing ownership behavior with an operation scope that 
recursively closes temporary handles, explicitly transfers long-lived handles, 
and rolls back failed initialization.
   
   Expected behavior: completed operations and failed resource initialization 
leave no bridge-owned Python references or partially registered resources 
behind.
   
   ### Version and environment
   
   - Affected code: current `main`; the ownership pattern also exists in the 
`release-0.3` production line
   - Local A/B: Flink 2.2.0, Pemja 0.5.7, Java 17, CPython 3.11.15, macOS
   
   ### Are you willing to submit a PR?
   
   - [x] I'm willing to submit a PR!
   


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