refactor(action): add shutdown method to ActionCore to close runner client and thread pool

This commit is contained in:
2026-04-09 12:00:32 +08:00
parent 1e46149d0a
commit 328befecca
6 changed files with 51 additions and 12 deletions

View File

@@ -16,6 +16,7 @@ import work.slhaf.partner.core.action.runner.RunnerClient;
import work.slhaf.partner.framework.agent.config.ConfigCenter; import work.slhaf.partner.framework.agent.config.ConfigCenter;
import work.slhaf.partner.framework.agent.factory.capability.annotation.CapabilityCore; import work.slhaf.partner.framework.agent.factory.capability.annotation.CapabilityCore;
import work.slhaf.partner.framework.agent.factory.capability.annotation.CapabilityMethod; import work.slhaf.partner.framework.agent.factory.capability.annotation.CapabilityMethod;
import work.slhaf.partner.framework.agent.factory.context.Shutdown;
import work.slhaf.partner.framework.agent.state.State; import work.slhaf.partner.framework.agent.state.State;
import work.slhaf.partner.framework.agent.state.StateSerializable; import work.slhaf.partner.framework.agent.state.StateSerializable;
import work.slhaf.partner.framework.agent.state.StateValue; import work.slhaf.partner.framework.agent.state.StateValue;
@@ -23,10 +24,7 @@ import work.slhaf.partner.framework.agent.state.StateValue;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.*; import java.util.*;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.*;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@SuppressWarnings("FieldMayBeFinal") @SuppressWarnings("FieldMayBeFinal")
@@ -58,6 +56,31 @@ public class ActionCore implements StateSerializable {
register(); register();
} }
@Shutdown
public void shutdown() {
try {
runnerClient.close();
} catch (Exception e) {
log.warn("runner client close error", e);
}
try {
platformExecutor.shutdown();
virtualExecutor.shutdown();
int count = 0;
if (!platformExecutor.awaitTermination(8, TimeUnit.SECONDS)) {
count += platformExecutor.shutdownNow().size();
}
if (!virtualExecutor.awaitTermination(8, TimeUnit.SECONDS)) {
count += virtualExecutor.shutdownNow().size();
}
if (count != 0) {
log.warn("{} tasks still running", count);
}
} catch (InterruptedException ignored) {
}
}
@CapabilityMethod @CapabilityMethod
public void putAction(@NonNull ExecutableAction executableAction) { public void putAction(@NonNull ExecutableAction executableAction) {
actionPool.removeIf(data -> data.getUuid().equals(executableAction.getUuid())); // 用来应对 ScheduledActionData 的重新排列 actionPool.removeIf(data -> data.getUuid().equals(executableAction.getUuid())); // 用来应对 ScheduledActionData 的重新排列

View File

@@ -115,8 +115,6 @@ public class LocalRunnerClient extends RunnerClient implements AutoCloseable {
this.mcpDescWatcher = descWatcher; this.mcpDescWatcher = descWatcher;
this.dynamicActionMcpManager = dynamicManager; this.dynamicActionMcpManager = dynamicManager;
this.mcpConfigWatcher = configWatcher; this.mcpConfigWatcher = configWatcher;
setupShutdownHook();
} }
private void registerPolicyProviders() { private void registerPolicyProviders() {
@@ -168,10 +166,6 @@ public class LocalRunnerClient extends RunnerClient implements AutoCloseable {
clientRegistry.register(id, client); clientRegistry.register(id, client);
} }
private void setupShutdownHook() {
Runtime.getRuntime().addShutdownHook(new Thread(this::close));
}
@Override @Override
public void close() { public void close() {
if (!closed.compareAndSet(false, true)) { if (!closed.compareAndSet(false, true)) {

View File

@@ -36,7 +36,7 @@ import java.util.concurrent.ExecutorService;
* </ol> * </ol>
*/ */
@Slf4j @Slf4j
public abstract class RunnerClient { public abstract class RunnerClient implements AutoCloseable {
protected final String ACTION_PATH; protected final String ACTION_PATH;

View File

@@ -53,4 +53,8 @@ public class SandboxRunnerClient extends RunnerClient {
throw new UnsupportedOperationException("Unimplemented method 'persistSerialize'"); throw new UnsupportedOperationException("Unimplemented method 'persistSerialize'");
} }
@Override
public void close() throws Exception {
}
} }

View File

@@ -11,6 +11,7 @@ import work.slhaf.partner.framework.agent.factory.capability.annotation.InjectCa
import work.slhaf.partner.framework.agent.factory.component.abstracts.AbstractAgentModule; import work.slhaf.partner.framework.agent.factory.component.abstracts.AbstractAgentModule;
import work.slhaf.partner.framework.agent.factory.component.annotation.Init; import work.slhaf.partner.framework.agent.factory.component.annotation.Init;
import work.slhaf.partner.framework.agent.factory.component.annotation.InjectModule; import work.slhaf.partner.framework.agent.factory.component.annotation.InjectModule;
import work.slhaf.partner.framework.agent.factory.context.Shutdown;
import work.slhaf.partner.module.action.executor.entity.*; import work.slhaf.partner.module.action.executor.entity.*;
import java.util.*; import java.util.*;
@@ -43,6 +44,8 @@ public class ActionExecutor extends AbstractAgentModule.Standalone {
private ExecutorService platformExecutor; private ExecutorService platformExecutor;
private RunnerClient runnerClient; private RunnerClient runnerClient;
private final AtomicBoolean closed = new AtomicBoolean(false);
@Init @Init
public void init() { public void init() {
virtualExecutor = actionCapability.getExecutor(ActionCore.ExecutorType.VIRTUAL); virtualExecutor = actionCapability.getExecutor(ActionCore.ExecutorType.VIRTUAL);
@@ -60,6 +63,11 @@ public class ActionExecutor extends AbstractAgentModule.Standalone {
blockManager.emitActionRecoveredBlock(recoveredActions); blockManager.emitActionRecoveredBlock(recoveredActions);
} }
@Shutdown
public void shutdown() {
closed.set(true);
}
public void execute(Action action) { public void execute(Action action) {
Future<?> future = virtualExecutor.submit(actionExecutionRouter(action)); Future<?> future = virtualExecutor.submit(actionExecutionRouter(action));
@@ -119,11 +127,16 @@ public class ActionExecutor extends AbstractAgentModule.Standalone {
} }
private void handleStateAction(StateAction stateAction) { private void handleStateAction(StateAction stateAction) {
if (closed.get()) {
return;
}
blockManager.emitStateActionTriggeredBlock(stateAction); blockManager.emitStateActionTriggeredBlock(stateAction);
stateAction.getTrigger().onTrigger(); stateAction.getTrigger().onTrigger();
} }
private void handleExecutableAction(ExecutableAction executableAction) { private void handleExecutableAction(ExecutableAction executableAction) {
actionCapability.putAction(executableAction);
val source = executableAction.getSource(); val source = executableAction.getSource();
val status = executableAction.getStatus(); val status = executableAction.getStatus();
if (status != Action.Status.PREPARE && status != Action.Status.EXECUTING) { if (status != Action.Status.PREPARE && status != Action.Status.EXECUTING) {
@@ -180,6 +193,9 @@ public class ActionExecutor extends AbstractAgentModule.Standalone {
}; };
stageCursor.init(); stageCursor.init();
do { do {
if (closed.get()) {
return;
}
val metaActions = actionChain.get(executableAction.getExecutingStage()); val metaActions = actionChain.get(executableAction.getExecutingStage());
val recognizerRecord = startRecognizerIfNeeded(executableAction, phaser); val recognizerRecord = startRecognizerIfNeeded(executableAction, phaser);
val listeningRecord = executeAndListening(metaActions, phaser, executableAction, source); val listeningRecord = executeAndListening(metaActions, phaser, executableAction, source);
@@ -187,6 +203,9 @@ public class ActionExecutor extends AbstractAgentModule.Standalone {
// synchronized 同步防止 accepting 循环间、phase guard 判定后发生 stage 推进 // synchronized 同步防止 accepting 循环间、phase guard 判定后发生 stage 推进
// 导致新行动的 phaser 投放阶段错乱无法阻塞的场景 // 导致新行动的 phaser 投放阶段错乱无法阻塞的场景
// 该 synchronized 将阶段推进与 accepting 监听 loop 捆绑为互斥的原子事件,避免了细粒度的 phaser 阶段竞态问题 // 该 synchronized 将阶段推进与 accepting 监听 loop 捆绑为互斥的原子事件,避免了细粒度的 phaser 阶段竞态问题
if (closed.get()) {
return;
}
synchronized (listeningRecord.accepting()) { synchronized (listeningRecord.accepting()) {
listeningRecord.accepting().set(false); listeningRecord.accepting().set(false);
// 立即尝试推进,本次推进中,如果前方仍有未执行 stage将执行一次阶段推进 // 立即尝试推进,本次推进中,如果前方仍有未执行 stage将执行一次阶段推进

View File

@@ -277,7 +277,6 @@ public class ActionPlanner extends AbstractAgentModule.Running<PartnerRunningFlo
} }
private void executeImmediateWithWatcher(ImmediateExecutableAction action) { private void executeImmediateWithWatcher(ImmediateExecutableAction action) {
actionCapability.putAction(action);
actionExecutor.execute(action); actionExecutor.execute(action);
AtomicBoolean notified = new AtomicBoolean(false); AtomicBoolean notified = new AtomicBoolean(false);