diff --git a/Partner-Main/src/main/java/work/slhaf/partner/core/action/entity/Action.kt b/Partner-Main/src/main/java/work/slhaf/partner/core/action/entity/Action.kt index 9a686bd1..46f5437a 100644 --- a/Partner-Main/src/main/java/work/slhaf/partner/core/action/entity/Action.kt +++ b/Partner-Main/src/main/java/work/slhaf/partner/core/action/entity/Action.kt @@ -27,7 +27,7 @@ sealed class Action { } -sealed interface Scheduled { +sealed interface Schedulable { val scheduleType: ScheduleType val scheduleContent: String @@ -103,17 +103,17 @@ sealed class ExecutableAction : Action() { } /** - * 计划行动数据类,继承自[Action],扩展了[Scheduled]相关调度属性,用于标识计划类型(单次还是周期性任务)和计划内容 + * 计划行动数据类,继承自[Action],扩展了[Schedulable]相关调度属性,用于标识计划类型(单次还是周期性任务)和计划内容 */ -data class ScheduledExecutableAction( +data class SchedulableExecutableAction( override val tendency: String, override val actionChain: MutableMap>, override val reason: String, override val description: String, override val source: String, - override val scheduleType: Scheduled.ScheduleType, + override val scheduleType: Schedulable.ScheduleType, override val scheduleContent: String -) : ExecutableAction(), Scheduled { +) : ExecutableAction(), Schedulable { val scheduleHistories = ArrayList() @@ -159,11 +159,11 @@ data class StateAction( override val reason: String, override val description: String, - override val scheduleType: Scheduled.ScheduleType, + override val scheduleType: Schedulable.ScheduleType, override val scheduleContent: String, val trigger: Trigger -) : Action(), Scheduled { +) : Action(), Schedulable { sealed interface Trigger { diff --git a/Partner-Main/src/main/java/work/slhaf/partner/module/modules/action/dispatcher/ActionDispatcher.java b/Partner-Main/src/main/java/work/slhaf/partner/module/modules/action/dispatcher/ActionDispatcher.java index ad20698f..33cac949 100644 --- a/Partner-Main/src/main/java/work/slhaf/partner/module/modules/action/dispatcher/ActionDispatcher.java +++ b/Partner-Main/src/main/java/work/slhaf/partner/module/modules/action/dispatcher/ActionDispatcher.java @@ -9,7 +9,7 @@ import work.slhaf.partner.core.action.ActionCapability; import work.slhaf.partner.core.action.ActionCore; import work.slhaf.partner.core.action.entity.ExecutableAction; import work.slhaf.partner.core.action.entity.ImmediateExecutableAction; -import work.slhaf.partner.core.action.entity.ScheduledExecutableAction; +import work.slhaf.partner.core.action.entity.SchedulableExecutableAction; import work.slhaf.partner.module.common.module.PostRunningModule; import work.slhaf.partner.module.modules.action.dispatcher.executor.ActionExecutor; import work.slhaf.partner.module.modules.action.dispatcher.executor.entity.ActionExecutorInput; @@ -48,10 +48,10 @@ public class ActionDispatcher extends PostRunningModule { String userId = context.getUserId(); val preparedActions = actionCapability.listActions(ExecutableAction.Status.PREPARE, userId); // 分类成PLANNING和IMMEDIATE两类 - Set scheduledActions = new HashSet<>(); + Set scheduledActions = new HashSet<>(); Set immediateActions = new HashSet<>(); for (ExecutableAction preparedAction : preparedActions) { - if (preparedAction instanceof ScheduledExecutableAction actionInfo) { + if (preparedAction instanceof SchedulableExecutableAction actionInfo) { scheduledActions.add(actionInfo); } else if (preparedAction instanceof ImmediateExecutableAction actionInfo) { immediateActions.add(actionInfo); diff --git a/Partner-Main/src/main/java/work/slhaf/partner/module/modules/action/dispatcher/executor/ActionExecutor.java b/Partner-Main/src/main/java/work/slhaf/partner/module/modules/action/dispatcher/executor/ActionExecutor.java index 0fe9fe96..d7ed0921 100644 --- a/Partner-Main/src/main/java/work/slhaf/partner/module/modules/action/dispatcher/executor/ActionExecutor.java +++ b/Partner-Main/src/main/java/work/slhaf/partner/module/modules/action/dispatcher/executor/ActionExecutor.java @@ -159,7 +159,7 @@ public class ActionExecutor extends AgentRunningSubModule, Void>() { +class ActionScheduler : AgentRunningSubModule, Void>() { @InjectCapability private lateinit var actionCapability: ActionCapability @@ -49,15 +49,15 @@ class ActionScheduler : AgentRunningSubModule, Vo @Init fun init() { - val listScheduledActions: () -> Set = { + val listScheduledActions: () -> Set = { actionCapability.listActions(null, null) .stream() - .filter { it is ScheduledExecutableAction } - .map { it as ScheduledExecutableAction } + .filter { it is SchedulableExecutableAction } + .map { it as SchedulableExecutableAction } .collect(Collectors.toSet()) } - val onTrigger: (Set) -> Unit = { actionExecutor.execute(ActionExecutorInput(it)) } + val onTrigger: (Set) -> Unit = { actionExecutor.execute(ActionExecutorInput(it)) } timeWheel = TimeWheel(listScheduledActions, onTrigger) @@ -72,7 +72,7 @@ class ActionScheduler : AgentRunningSubModule, Vo } // TODO 如果要将 TimeWheel 作为 Agent 内部的循环周期,那么不依赖 Action 链路的内容,将不适合参与到 ActionExecutor,因此需要将 ActionData 的触发类型进行分类:SILENT TRIGGER(仅限更新 ActionData 内部状态,通过属性 copy 完成,不开放过多权限,防止序列化失败)、EXECUTOR、AGENT TURN。考虑将时间轮下放至 ActionCapability,作为底层行动语义的一部分 - override fun execute(scheduledActionDataSet: Set?): Void? { + override fun execute(scheduledActionDataSet: Set?): Void? { schedulerScope.launch { scheduledActionDataSet?.run { for (scheduledActionData in scheduledActionDataSet) { @@ -86,12 +86,12 @@ class ActionScheduler : AgentRunningSubModule, Vo } private class TimeWheel( - val listScheduledActions: () -> Set, - val onTrigger: (toTrigger: Set) -> Unit + val listScheduledActions: () -> Set, + val onTrigger: (toTrigger: Set) -> Unit ) : Closeable { - private val actionsGroupByHour = Array>(24) { mutableSetOf() } - private val wheel = Array>(60 * 60) { mutableSetOf() } + private val actionsGroupByHour = Array>(24) { mutableSetOf() } + private val wheel = Array>(60 * 60) { mutableSetOf() } private var recordHour: Int = -1 private var recordDay: Int = -1 private val state = MutableStateFlow(WheelState.SLEEPING) @@ -110,7 +110,7 @@ class ActionScheduler : AgentRunningSubModule, Vo launchWheel() } - suspend fun schedule(actionData: ScheduledExecutableAction) { + suspend fun schedule(actionData: SchedulableExecutableAction) { if (actionData.status != ExecutableAction.Status.PREPARE) { return } @@ -142,9 +142,9 @@ class ActionScheduler : AgentRunningSubModule, Vo private fun launchWheel() { - fun collectToTrigger(tick: Int, previousTick: Int, triggerHour: Int): Set? { + fun collectToTrigger(tick: Int, previousTick: Int, triggerHour: Int): Set? { if (tick > previousTick) { - val toTrigger = mutableSetOf() + val toTrigger = mutableSetOf() for (i in previousTick..tick) { val bucket = wheel[i] if (bucket.isNotEmpty()) { @@ -179,7 +179,7 @@ class ActionScheduler : AgentRunningSubModule, Vo nextTickNanos += step.toLong() * 1_000_000_000L var shouldBreak = false - var toTrigger: Set? = null + var toTrigger: Set? = null checkThenExecute(false) { if (it.hour != launchingHour) { @@ -266,9 +266,9 @@ class ActionScheduler : AgentRunningSubModule, Vo suspend fun checkThenExecute(finallyToExecute: Boolean = true, then: (currentTime: ZonedDateTime) -> Unit) = wheelActionsLock.withLock { fun loadActions( - source: Set, + source: Set, now: ZonedDateTime, - load: (latestExecutingTime: ZonedDateTime, actionData: ScheduledExecutableAction) -> Unit, + load: (latestExecutingTime: ZonedDateTime, actionData: SchedulableExecutableAction) -> Unit, repair: () -> Unit ) { val runLoading = { @@ -292,7 +292,8 @@ class ActionScheduler : AgentRunningSubModule, Vo } fun loadHourActions(currentTime: ZonedDateTime) { - val load: (ZonedDateTime, ScheduledExecutableAction) -> Unit = { latestExecutionTime, actionData -> + val load: (ZonedDateTime, SchedulableExecutableAction) -> Unit = + { latestExecutionTime, actionData -> val secondsTime = latestExecutionTime.minute * 60 + latestExecutionTime.second wheel[secondsTime].add(actionData) log.debug("Action loaded to hour: {}", actionData) @@ -308,7 +309,8 @@ class ActionScheduler : AgentRunningSubModule, Vo } fun loadDayActions(currentTime: ZonedDateTime) { - val load: (ZonedDateTime, ScheduledExecutableAction) -> Unit = { latestExecutingTime, actionData -> + val load: (ZonedDateTime, SchedulableExecutableAction) -> Unit = + { latestExecutingTime, actionData -> actionsGroupByHour[latestExecutingTime.hour].add(actionData) log.debug("Action loaded to day: {}", actionData) } @@ -348,12 +350,12 @@ class ActionScheduler : AgentRunningSubModule, Vo } private fun parseToZonedDateTime( - scheduleType: Scheduled.ScheduleType, + scheduleType: Schedulable.ScheduleType, scheduleContent: String, now: ZonedDateTime ): ZonedDateTime? { return when (scheduleType) { - Scheduled.ScheduleType.CYCLE + Schedulable.ScheduleType.CYCLE -> { val cron = try { cronParser.parse(scheduleContent).validate() @@ -364,7 +366,7 @@ class ActionScheduler : AgentRunningSubModule, Vo executionTime.nextExecution(now).getOrNull() } - Scheduled.ScheduleType.ONCE -> { + Schedulable.ScheduleType.ONCE -> { val executionTime = try { ZonedDateTime.parse(scheduleContent) } catch (_: Exception) { @@ -380,7 +382,7 @@ class ActionScheduler : AgentRunningSubModule, Vo } - private fun logFailedStatus(actionData: ScheduledExecutableAction) { + private fun logFailedStatus(actionData: SchedulableExecutableAction) { log.warn( "行动未加载,uuid: {}, source: {}, tendency: {}, scheduleContent: {}", actionData.uuid, diff --git a/Partner-Main/src/main/java/work/slhaf/partner/module/modules/action/planner/ActionPlanner.java b/Partner-Main/src/main/java/work/slhaf/partner/module/modules/action/planner/ActionPlanner.java index 3e89a137..f45242eb 100644 --- a/Partner-Main/src/main/java/work/slhaf/partner/module/modules/action/planner/ActionPlanner.java +++ b/Partner-Main/src/main/java/work/slhaf/partner/module/modules/action/planner/ActionPlanner.java @@ -234,7 +234,7 @@ public class ActionPlanner extends PreRunningModule { private ExecutableAction buildActionData(EvaluatorResult evaluatorResult, String userId) { Map> actionChain = getActionChain(evaluatorResult); return switch (evaluatorResult.getType()) { - case PLANNING -> new ScheduledExecutableAction( + case PLANNING -> new SchedulableExecutableAction( evaluatorResult.getTendency(), actionChain, evaluatorResult.getReason(), diff --git a/Partner-Main/src/main/java/work/slhaf/partner/module/modules/action/planner/evaluator/entity/EvaluatorResult.java b/Partner-Main/src/main/java/work/slhaf/partner/module/modules/action/planner/evaluator/entity/EvaluatorResult.java index 4b52edc0..79266942 100644 --- a/Partner-Main/src/main/java/work/slhaf/partner/module/modules/action/planner/evaluator/entity/EvaluatorResult.java +++ b/Partner-Main/src/main/java/work/slhaf/partner/module/modules/action/planner/evaluator/entity/EvaluatorResult.java @@ -1,7 +1,7 @@ package work.slhaf.partner.module.modules.action.planner.evaluator.entity; import lombok.Data; -import work.slhaf.partner.core.action.entity.ScheduledExecutableAction; +import work.slhaf.partner.core.action.entity.SchedulableExecutableAction; import java.util.List; import java.util.Map; @@ -12,7 +12,7 @@ public class EvaluatorResult { private boolean needConfirm; private ActionType type; private String scheduleContent; - private ScheduledExecutableAction.ScheduleType scheduleType; + private SchedulableExecutableAction.ScheduleType scheduleType; private Map> primaryActionChain; private String tendency; private String reason; diff --git a/Partner-Main/src/test/java/work/slhaf/partner/module/modules/action/dispatcher/executor/ActionSchedulerTest.kt b/Partner-Main/src/test/java/work/slhaf/partner/module/modules/action/dispatcher/executor/ActionSchedulerTest.kt index 8e6cf93f..bec34077 100644 --- a/Partner-Main/src/test/java/work/slhaf/partner/module/modules/action/dispatcher/executor/ActionSchedulerTest.kt +++ b/Partner-Main/src/test/java/work/slhaf/partner/module/modules/action/dispatcher/executor/ActionSchedulerTest.kt @@ -15,8 +15,8 @@ import org.mockito.junit.jupiter.MockitoExtension import org.slf4j.LoggerFactory import work.slhaf.partner.core.action.ActionCapability import work.slhaf.partner.core.action.entity.ExecutableAction -import work.slhaf.partner.core.action.entity.Scheduled -import work.slhaf.partner.core.action.entity.ScheduledExecutableAction +import work.slhaf.partner.core.action.entity.Schedulable +import work.slhaf.partner.core.action.entity.SchedulableExecutableAction import work.slhaf.partner.module.modules.action.dispatcher.executor.entity.ActionExecutorInput import work.slhaf.partner.module.modules.action.dispatcher.scheduler.ActionScheduler import java.time.ZonedDateTime @@ -61,14 +61,14 @@ class ActionSchedulerTest { @Test fun `running test`() { - fun buildAction(time: ZonedDateTime): ScheduledExecutableAction { - return ScheduledExecutableAction( + fun buildAction(time: ZonedDateTime): SchedulableExecutableAction { + return SchedulableExecutableAction( "tendency", mutableMapOf(), "reason", "description", "source", - Scheduled.ScheduleType.ONCE, + Schedulable.ScheduleType.ONCE, time.toString() ) } @@ -116,7 +116,7 @@ class ActionSchedulerTest { // 场景编号:2;路径:B2 → B2.3;目的:验证正常入轮与副作用 initTimeWheelWithPrimaryActions(emptySet()) val action = buildScheduledAction( - type = Scheduled.ScheduleType.ONCE, + type = Schedulable.ScheduleType.ONCE, ZonedDateTime.now().plusHours(1).toString() ) @@ -133,7 +133,7 @@ class ActionSchedulerTest { // 场景编号:3;路径:B2 → B2.1;目的:验证忽略非 PREPARE 状态 initTimeWheelWithPrimaryActions(emptySet()) val action = buildScheduledAction( - type = Scheduled.ScheduleType.ONCE + type = Schedulable.ScheduleType.ONCE ) actionScheduler.execute(setOf(action)) @@ -148,7 +148,7 @@ class ActionSchedulerTest { // 场景编号:4;路径:B2 → B2.2;目的:验证解析失败被跳过 initTimeWheelWithPrimaryActions(emptySet()) val action = buildScheduledAction( - type = Scheduled.ScheduleType.ONCE + type = Schedulable.ScheduleType.ONCE ) actionScheduler.execute(setOf(action)) @@ -162,7 +162,7 @@ class ActionSchedulerTest { // 场景编号:5;路径:B2 → B2.2;目的:验证 cron 解析失败被跳过 initTimeWheelWithPrimaryActions(emptySet()) val action = buildScheduledAction( - type = Scheduled.ScheduleType.CYCLE, + type = Schedulable.ScheduleType.CYCLE, scheduleContentOverride = "invalid-cron" ) @@ -177,7 +177,7 @@ class ActionSchedulerTest { // 场景编号:6;路径:B2 异常中断;目的:验证异常传播 initTimeWheelWithPrimaryActions(emptySet()) val action = buildScheduledAction( - type = Scheduled.ScheduleType.ONCE + type = Schedulable.ScheduleType.ONCE ) Mockito.doThrow(RuntimeException("boom")) .`when`(actionCapability) @@ -193,7 +193,7 @@ class ActionSchedulerTest { // 场景编号:7;路径:B2.3;目的:验证同小时调度触发 ACTIVE initTimeWheelWithPrimaryActions(emptySet()) val action = buildScheduledAction( - type = Scheduled.ScheduleType.ONCE, + type = Schedulable.ScheduleType.ONCE, scheduleContentOverride = ZonedDateTime.now().plusMinutes(2).toString() ) @@ -212,16 +212,16 @@ class ActionSchedulerTest { // 场景编号:15;路径:B2 + B2.1/B2.2/B2.3;目的:验证混合输入行为 initTimeWheelWithPrimaryActions(emptySet()) val ok = buildScheduledAction( - type = Scheduled.ScheduleType.ONCE, + type = Schedulable.ScheduleType.ONCE, scheduleContentOverride = ZonedDateTime.now().plusMinutes(2).toString() ) val nonPrepare = buildScheduledAction( - type = Scheduled.ScheduleType.ONCE, + type = Schedulable.ScheduleType.ONCE, scheduleContentOverride = ZonedDateTime.now().plusMinutes(2).toString() ) nonPrepare.status = ExecutableAction.Status.FAILED val invalid = buildScheduledAction( - type = Scheduled.ScheduleType.CYCLE, + type = Schedulable.ScheduleType.CYCLE, scheduleContentOverride = "invalid-cron" ) @@ -236,7 +236,7 @@ class ActionSchedulerTest { assertFalse(allScheduled.contains(invalid)) } - private fun initTimeWheelWithPrimaryActions(actions: Set) { + private fun initTimeWheelWithPrimaryActions(actions: Set) { @Suppress("UNCHECKED_CAST") Mockito.`when`(actionCapability.listActions(null, null)) .thenReturn(actions as Set) @@ -244,10 +244,10 @@ class ActionSchedulerTest { } private fun buildScheduledAction( - type: Scheduled.ScheduleType, + type: Schedulable.ScheduleType, scheduleContentOverride: String? = null - ): ScheduledExecutableAction { - val action = ScheduledExecutableAction( + ): SchedulableExecutableAction { + val action = SchedulableExecutableAction( "test", mutableMapOf(), "reason", @@ -259,7 +259,7 @@ class ActionSchedulerTest { return action } - private fun ScheduledExecutableAction.scheduleContentHour(): Int { + private fun SchedulableExecutableAction.scheduleContentHour(): Int { return ZonedDateTime.parse(this.scheduleContent).hour } @@ -270,14 +270,14 @@ class ActionSchedulerTest { } @Suppress("UNCHECKED_CAST") - private fun actionsGroupByHour(timeWheel: Any): Array> { + private fun actionsGroupByHour(timeWheel: Any): Array> { val field = timeWheel.javaClass.getDeclaredField("actionsGroupByHour") field.isAccessible = true - return field.get(timeWheel) as Array> + return field.get(timeWheel) as Array> } - private fun allScheduledActions(timeWheel: Any): Set { - val result = linkedSetOf() + private fun allScheduledActions(timeWheel: Any): Set { + val result = linkedSetOf() for (bucket in actionsGroupByHour(timeWheel)) { result.addAll(bucket) }