From e4e91b46d0ce781e7dc87dcdf0d2909b01911d4b Mon Sep 17 00:00:00 2001
From: Junjie <fallin.jie@qq.com>
Date: 星期一, 27 四月 2026 12:34:31 +0800
Subject: [PATCH] fix: harden auto tune scheduler throttling
---
src/test/java/com/zy/ai/service/AutoTuneCoordinatorServiceImplTest.java | 89 ++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 88 insertions(+), 1 deletions(-)
diff --git a/src/test/java/com/zy/ai/service/AutoTuneCoordinatorServiceImplTest.java b/src/test/java/com/zy/ai/service/AutoTuneCoordinatorServiceImplTest.java
index 70bd28d..2f880c2 100644
--- a/src/test/java/com/zy/ai/service/AutoTuneCoordinatorServiceImplTest.java
+++ b/src/test/java/com/zy/ai/service/AutoTuneCoordinatorServiceImplTest.java
@@ -49,6 +49,8 @@
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -308,7 +310,7 @@
when(configService.getConfigValue("aiAutoTuneIntervalMinutes", "10")).thenReturn("10");
when(wrkMastService.count(any(Wrapper.class))).thenReturn(1L);
when(redisUtil.get(RedisKeyType.AI_AUTO_TUNE_LAST_TRIGGER_GUARD.key)).thenReturn(null);
- when(aiAutoTuneJobService.list(any(Wrapper.class))).thenReturn(Collections.emptyList(), Collections.emptyList());
+ when(aiAutoTuneJobService.list(any(Wrapper.class))).thenReturn(Collections.emptyList());
when(redisUtil.trySetStringIfAbsent(anyString(), anyString(), anyLong())).thenReturn(true);
when(autoTuneAgentService.runAutoTune(AutoTuneTriggerType.AUTO.getCode())).thenReturn(agentResult);
@@ -320,6 +322,62 @@
verify(autoTuneAgentService).runAutoTune(AutoTuneTriggerType.AUTO.getCode());
verify(operateLogService).save(any());
verify(redisUtil).set(anyString(), any(), anyLong());
+ verify(redisUtil).compareAndDelete(anyString(), anyString());
+ }
+
+ @Test
+ void coordinatorKeepsAgentResultWhenOperateLogFails() {
+ AutoTuneAgentService.AutoTuneAgentResult agentResult = successfulAgentResult();
+ when(configService.getConfigValue("aiAutoTuneEnabled", "N")).thenReturn("Y");
+ when(configService.getConfigValue("aiAutoTuneIntervalMinutes", "10")).thenReturn("10");
+ when(wrkMastService.count(any(Wrapper.class))).thenReturn(1L);
+ when(redisUtil.get(RedisKeyType.AI_AUTO_TUNE_LAST_TRIGGER_GUARD.key)).thenReturn(null);
+ when(aiAutoTuneJobService.list(any(Wrapper.class))).thenReturn(Collections.emptyList());
+ when(redisUtil.trySetStringIfAbsent(anyString(), anyString(), anyLong())).thenReturn(true);
+ when(autoTuneAgentService.runAutoTune(AutoTuneTriggerType.AUTO.getCode())).thenReturn(agentResult);
+ doThrow(new RuntimeException("log failed")).when(operateLogService).save(any());
+
+ AutoTuneCoordinatorService.AutoTuneCoordinatorResult result = coordinatorService().runAutoTuneIfEligible();
+
+ assertFalse(result.getSkipped());
+ assertTrue(result.getTriggered());
+ assertSame(agentResult, result.getAgentResult());
+ verify(redisUtil).compareAndDelete(anyString(), anyString());
+ }
+
+ @Test
+ void coordinatorSetsGuardWhenAgentReturnsFailure() {
+ AutoTuneAgentService.AutoTuneAgentResult agentResult = failedAgentResult();
+ when(configService.getConfigValue("aiAutoTuneEnabled", "N")).thenReturn("Y");
+ when(configService.getConfigValue("aiAutoTuneIntervalMinutes", "10")).thenReturn("10");
+ when(wrkMastService.count(any(Wrapper.class))).thenReturn(1L);
+ when(redisUtil.get(RedisKeyType.AI_AUTO_TUNE_LAST_TRIGGER_GUARD.key)).thenReturn(null);
+ when(aiAutoTuneJobService.list(any(Wrapper.class))).thenReturn(Collections.emptyList());
+ when(redisUtil.trySetStringIfAbsent(anyString(), anyString(), anyLong())).thenReturn(true);
+ when(autoTuneAgentService.runAutoTune(AutoTuneTriggerType.AUTO.getCode())).thenReturn(agentResult);
+
+ AutoTuneCoordinatorService.AutoTuneCoordinatorResult result = coordinatorService().runAutoTuneIfEligible();
+
+ assertFalse(result.getSkipped());
+ assertSame(agentResult, result.getAgentResult());
+ verify(redisUtil).set(eq(RedisKeyType.AI_AUTO_TUNE_LAST_TRIGGER_GUARD.key), any(), eq(600L));
+ }
+
+ @Test
+ void coordinatorSetsGuardWhenAgentThrows() {
+ when(configService.getConfigValue("aiAutoTuneEnabled", "N")).thenReturn("Y");
+ when(configService.getConfigValue("aiAutoTuneIntervalMinutes", "10")).thenReturn("10");
+ when(wrkMastService.count(any(Wrapper.class))).thenReturn(1L);
+ when(redisUtil.get(RedisKeyType.AI_AUTO_TUNE_LAST_TRIGGER_GUARD.key)).thenReturn(null);
+ when(aiAutoTuneJobService.list(any(Wrapper.class))).thenReturn(Collections.emptyList());
+ when(redisUtil.trySetStringIfAbsent(anyString(), anyString(), anyLong())).thenReturn(true);
+ when(autoTuneAgentService.runAutoTune(AutoTuneTriggerType.AUTO.getCode())).thenThrow(new RuntimeException("agent failed"));
+
+ AutoTuneCoordinatorService.AutoTuneCoordinatorResult result = coordinatorService().runAutoTuneIfEligible();
+
+ assertFalse(result.getSkipped());
+ assertFalse(result.getAgentResult().getSuccess());
+ verify(redisUtil).set(eq(RedisKeyType.AI_AUTO_TUNE_LAST_TRIGGER_GUARD.key), any(), eq(600L));
verify(redisUtil).compareAndDelete(anyString(), anyString());
}
@@ -402,6 +460,28 @@
assertTrue(visibleToolNames.contains("wcs_local_dispatch_apply_auto_tune_changes"));
assertTrue(visibleToolNames.contains("wcs_local_dispatch_revert_last_auto_tune_job"));
assertFalse(visibleToolNames.contains("wcs_local_device_get_crn_status"));
+ }
+
+ @Test
+ void agentForcesAutoTriggerTypeOnApplyTools() {
+ AutoTuneAgentServiceImpl service = agentService();
+ when(mcpToolManager.buildOpenAiTools()).thenReturn(allowedOpenAiTools());
+ when(mcpToolManager.callTool(any(), any(JSONObject.class))).thenReturn(Collections.singletonMap("ok", true));
+ when(llmChatService.chatCompletion(any(), anyDouble(), anyInt(), any()))
+ .thenReturn(
+ response("snapshot", toolCall("call_1", "wcs_local_dispatch_get_auto_tune_snapshot",
+ "{}"), 10, 5),
+ response("dry run", toolCall("call_2", "wcs_local_dispatch_apply_auto_tune_changes",
+ "{\"dryRun\":true,\"changes\":[]}"), 10, 5),
+ response("done", null, 10, 5)
+ );
+
+ AutoTuneAgentService.AutoTuneAgentResult result = service.runAutoTune("auto");
+
+ assertTrue(result.getSuccess());
+ ArgumentCaptor<JSONObject> argumentCaptor = ArgumentCaptor.forClass(JSONObject.class);
+ verify(mcpToolManager).callTool(eq("wcs_local_dispatch_apply_auto_tune_changes"), argumentCaptor.capture());
+ assertEquals("auto", argumentCaptor.getValue().getString("triggerType"));
}
@Test
@@ -496,6 +576,13 @@
return result;
}
+ private AutoTuneAgentService.AutoTuneAgentResult failedAgentResult() {
+ AutoTuneAgentService.AutoTuneAgentResult result = successfulAgentResult();
+ result.setSuccess(false);
+ result.setSummary("failed");
+ return result;
+ }
+
private AutoTuneChangeCommand change(String targetType, String targetId, String targetKey, String newValue) {
AutoTuneChangeCommand command = new AutoTuneChangeCommand();
command.setTargetType(targetType);
--
Gitblit v1.9.1