Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,20 @@ public final class AgentScopeJvmShutdownHook {

private AgentScopeJvmShutdownHook() {}

/**
* Resets the REGISTERED flag for testing purposes.
*
* <p>This method is intended for testing only. It allows tests to verify
* the JVM hook registration behavior in isolation.
*/
static void resetForTesting() {
REGISTERED.set(false);
}

public static void register(GracefulShutdownManager manager) {
if (!manager.getConfig().isRegister()) {
return;
}
if (!REGISTERED.compareAndSet(false, true)) {
return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,20 @@
* <ul>
* <li>Maximum time to wait for ongoing operations to complete</li>
* <li>Policy for handling partial reasoning results</li>
* <li>Policy for control register jvm shutdown hook</li>
* </ul>
*
* @param shutdownTimeout maximum duration to wait for shutdown completion;
* if null, the system will wait indefinitely for all operations
* to complete; if specified, must be a positive duration
* @param partialReasoningPolicy policy for handling incomplete reasoning results during shutdown;
* cannot be null
* @param isRegister Policy for control register jvm shutdown hook
*/
public record GracefulShutdownConfig(
Duration shutdownTimeout, PartialReasoningPolicy partialReasoningPolicy) {
Duration shutdownTimeout,
PartialReasoningPolicy partialReasoningPolicy,
boolean isRegister) {

/**
* Default configuration instance.
Expand All @@ -43,10 +47,25 @@ public record GracefulShutdownConfig(
* <ul>
* <li>Shutdown timeout: null (wait indefinitely)</li>
* <li>Partial reasoning policy: {@link PartialReasoningPolicy#SAVE}</li>
* <li>Is register jvm shutdownHook: {@code false}</li>
* </ul>
*/
public static final GracefulShutdownConfig DEFAULT =
new GracefulShutdownConfig(null, PartialReasoningPolicy.SAVE);
new GracefulShutdownConfig(null, PartialReasoningPolicy.SAVE, false);

/**
*
*
* <p>Uses the following settings:
* <ul>
* <li>Shutdown timeout: null (wait indefinitely)</li>
* <li>Partial reasoning policy: {@link PartialReasoningPolicy#SAVE}</li>
* </ul>
*/
public GracefulShutdownConfig(
Duration shutdownTimeout, PartialReasoningPolicy partialReasoningPolicy) {
this(shutdownTimeout, partialReasoningPolicy, false);
}

/**
* Compact constructor for validation.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,35 @@ void configRejectsInvalidTimeout() {
void configRejectsNullPolicy() {
assertThrows(NullPointerException.class, () -> new GracefulShutdownConfig(null, null));
}

@Test
@DisplayName("DEFAULT config has isRegister set to false")
void defaultConfigJvmHookDisabled() {
GracefulShutdownConfig cfg = GracefulShutdownConfig.DEFAULT;
assertFalse(cfg.isRegister());
}

@Test
@DisplayName("2-param constructor sets isRegister to false")
void twoParamConstructorJvmHookEnabled() {
GracefulShutdownConfig cfg =
new GracefulShutdownConfig(Duration.ofSeconds(10), PartialReasoningPolicy.SAVE);
assertFalse(cfg.isRegister());
}

@Test
@DisplayName("3-param constructor allows explicit isRegister value")
void threeParamConstructorExplicitValue() {
GracefulShutdownConfig cfgWithHook =
new GracefulShutdownConfig(
Duration.ofSeconds(10), PartialReasoningPolicy.SAVE, true);
assertTrue(cfgWithHook.isRegister());

GracefulShutdownConfig cfgWithoutHook =
new GracefulShutdownConfig(
Duration.ofSeconds(10), PartialReasoningPolicy.SAVE, false);
assertFalse(cfgWithoutHook.isRegister());
}
}

// ==================== GracefulShutdownManager ====================
Expand Down Expand Up @@ -576,6 +605,40 @@ void unrelatedEventsPassThrough() {
}
}

// ==================== AgentScopeJvmShutdownHook ====================

@Nested
@DisplayName("AgentScopeJvmShutdownHook")
class JvmShutdownHookTests {

@Test
@DisplayName("register does nothing when isRegister is false")
void registerSkippedWhenDisabled() {
AgentScopeJvmShutdownHook.resetForTesting();
manager.setConfig(
new GracefulShutdownConfig(
Duration.ofSeconds(10), PartialReasoningPolicy.SAVE, false));

// Should not throw and should not register the hook
assertDoesNotThrow(() -> AgentScopeJvmShutdownHook.register(manager));
}

@Test
@DisplayName("register is idempotent when isRegister is true")
void registerIdempotentWhenEnabled() {
AgentScopeJvmShutdownHook.resetForTesting();
manager.setConfig(
new GracefulShutdownConfig(
Duration.ofSeconds(10), PartialReasoningPolicy.SAVE, true));

// First call should succeed
assertDoesNotThrow(() -> AgentScopeJvmShutdownHook.register(manager));

// Second call should also succeed (idempotent)
assertDoesNotThrow(() -> AgentScopeJvmShutdownHook.register(manager));
}
}

// ==================== AgentShuttingDownException ====================

@Nested
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,9 @@ public class AgentService {
@Value("${agent.shutdown-partial-reasoning-policy:save}")
private String partialReasoningPolicy;

@Value("${agent.shutdown-hook-is-register:true}")
private boolean isRegister;

@PostConstruct
public void initShutdownConfig() {
Duration gracefulShutdownTime =
Expand All @@ -100,7 +103,7 @@ public void initShutdownConfig() {
GracefulShutdownManager.getInstance()
.setConfig(
new GracefulShutdownConfig(
gracefulShutdownTime, shutdownPartialReasoningPolicy));
gracefulShutdownTime, shutdownPartialReasoningPolicy, isRegister));
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,8 @@ private static void scenario1_toolExecutionTimeout(String apiKey, Session sessio

shutdownManager.resetForTesting();
shutdownManager.setConfig(
new GracefulShutdownConfig(Duration.ofSeconds(5), PartialReasoningPolicy.SAVE));
new GracefulShutdownConfig(
Duration.ofSeconds(5), PartialReasoningPolicy.SAVE, true));

Toolkit toolkit = new Toolkit();
toolkit.registerTool(new DataAnalysisTool());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,5 @@ dashscope:
agent:
model-name: qwen3.5-plus
shutdown-timeout-seconds: -1
shutdown-partial-reasoning-policy: save
shutdown-partial-reasoning-policy: save
shutdown-hook-is-register: true
Loading