From 9fc0eed4993bd7597f65c13be394482c1c2dd42b Mon Sep 17 00:00:00 2001 From: James Maes Date: Thu, 15 Oct 2026 15:53:47 -0500 Subject: [PATCH] fix(runtime): shutdown hook holds the runtime weakly Every AssistantRuntime registered a JVM shutdown hook that held the runtime, and so its whole QInstance, until JVM exit. A host test suite that builds an instance per test leaked every instance (kof22's suite ran out of heap). The hook now holds a weak reference. Co-Authored-By: Claude Opus 5.5 --- .../qbits/assistant/AssistantRuntime.java | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/qbit-assistant/src/main/java/com/kingsrook/qbits/assistant/AssistantRuntime.java b/qbit-assistant/src/main/java/com/kingsrook/qbits/assistant/AssistantRuntime.java index 522cca2..923f50d 100644 --- a/qbit-assistant/src/main/java/com/kingsrook/qbits/assistant/AssistantRuntime.java +++ b/qbit-assistant/src/main/java/com/kingsrook/qbits/assistant/AssistantRuntime.java @@ -17,6 +17,7 @@ package com.kingsrook.qbits.assistant; +import java.lang.ref.WeakReference; import java.net.InetAddress; import java.time.Clock; import java.time.Duration; @@ -178,11 +179,22 @@ public class AssistantRuntime this.contextBuilder = new ContextBuilder(config, kernel, toolbox).withKnowledgeTool(knowledgeTool).withBulkLoadTools(bulkLoadTools); if(Boolean.TRUE.equals(config.getRegisterShutdownHook())) { + /////////////////////////////////////////////////////////////////////// + // the hook holds the runtime weakly: a runtime (and its QInstance) // + // that is dropped without shutdown() - every test that builds an // + // instance - must not stay reachable from the JVM's hooks // + /////////////////////////////////////////////////////////////////////// + WeakReference self = new WeakReference<>(this); + Integer graceSeconds = config.getShutdownGraceSeconds(); shutdownHook = new Thread(() -> { try { - shutdown(Duration.ofSeconds(config.getShutdownGraceSeconds())); + AssistantRuntime runtime = self.get(); + if(runtime != null) + { + runtime.shutdown(Duration.ofSeconds(graceSeconds)); + } } catch(Throwable ignored) { -- 2.54.0