Repository navigation
Conversation
…xpire A fact inserted with the dynamic flag, insert(obj, true), is recorded in NamedEntryPoint.dynamicFacts and has the entry point registered as its PropertyChangeListener. Deleting it only undid that when the fact's type was declared dynamic, so for any other type the handle, the fact and the listener stayed referenced until the session was disposed. A long-running session that keeps inserting and deleting dynamic facts grows until OutOfMemoryError. Release the listener whenever the fact is dynamic, either through its type or through the insert flag. Do the same when an event expires, which removed the handle from the object store without releasing the listener at all. Logical inserts never register a listener, so the TMS paths need no change. A class annotated with @PropertyChangeSupport now makes its type dynamic, the same as declaring it with @propertyChangeSupport in DRL. Before, only the DRL declaration had that effect and the class annotation was ignored.
49b7aa9 to
b70bdb8
Compare
|
Also PASS: DynamicFactMarshallingTest |
There was a problem hiding this comment.
🟢 Approval recommended
The focused implementation addresses both reported leaks with appropriate regression coverage.
0 open findings
What changed in this PR
Fixes listener leaks for dynamic facts and honors class-level property-change annotations.
Changes:
- Unregisters listeners when dynamic facts are deleted or expire.
- Enables dynamic behavior for class-level
@PropertyChangeSupport. - Adds regression tests for deletion, annotation handling, and expiry.
| File | Description |
|---|---|
PropertyChangeSupportTest.java |
Adds listener lifecycle regression tests. |
NamedEntryPoint.java |
Centralizes listener cleanup across deletion paths. |
TypeDeclaration.java |
Processes class-level property-change annotations. |
🧠 Review effort: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
|
GHA |
|
@Thebas Thanks for the fix — the listener leak on delete and expiry is clearly the right thing to address, and the tests are solid. I found one concurrency issue with the expiry path that I think should be fixed before merging.
|
…expiry insert() adds to dynamicFacts while holding the entry point lock, but an expiring event reaches removeFromObjectStore() from the agenda without it, so releasing its listener could touch the HashSet concurrently with an insert on another thread. Take the lock around the listener release there; the delete path already runs under it.
|
Dear @tkobayas . Fixed it. Thank you. |
|
I can not take credit for this. Bob picked it up for me ( AI ). But it looks like if the DRL definition does not have the annotation, then the annotation gets ignored. The PR should have a fix and a test for this. |
There was a problem hiding this comment.
Warning
Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.
Copilot review overview
1 open finding
🧠 Review effort: Lite
| ksession.fireAllRules(); | ||
| assertThat(fact.getListenerCount()).isEqualTo(1); | ||
|
|
||
| SessionPseudoClock clock = ksession.getSessionClock(); |

Issue:
Bug 1: delete never released facts inserted with insert(obj, true) (NamedEntryPoint.java)
Bug 2: class-level @PropertyChangeSupport was ignored (TypeDeclaration.java)
Tests (in PropertyChangeSupportTest). Each one checks that the bean's own listener count drops to 0:
Results