This is an automated email from the ASF dual-hosted git repository. yuluo-yx pushed a commit to branch 0725-yuluo/fix in repository https://gitbox.apache.org/repos/asf/hertzbeat.git
commit 1aab0159be0d9a43157a8b99370357c27e84a043 Author: yuluo-yx <[email protected]> AuthorDate: Sat Jul 25 18:22:52 2026 +0800 fix(ai): remove SOP schedules when deleting conversations Signed-off-by: yuluo-yx <[email protected]> --- .../ai/service/impl/ConversationServiceImpl.java | 6 +++++ .../service/impl/ConversationServiceImplTest.java | 28 ++++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/hertzbeat-ai/src/main/java/org/apache/hertzbeat/ai/service/impl/ConversationServiceImpl.java b/hertzbeat-ai/src/main/java/org/apache/hertzbeat/ai/service/impl/ConversationServiceImpl.java index 1adbe6f78c..c86ada857c 100644 --- a/hertzbeat-ai/src/main/java/org/apache/hertzbeat/ai/service/impl/ConversationServiceImpl.java +++ b/hertzbeat-ai/src/main/java/org/apache/hertzbeat/ai/service/impl/ConversationServiceImpl.java @@ -23,6 +23,7 @@ import java.util.Optional; import lombok.extern.slf4j.Slf4j; import org.apache.hertzbeat.ai.dao.ChatConversationDao; import org.apache.hertzbeat.ai.dao.ChatMessageDao; +import org.apache.hertzbeat.ai.dao.SopScheduleDao; import org.apache.hertzbeat.ai.pojo.dto.ChatRequestContext; import org.apache.hertzbeat.ai.pojo.dto.ChatResponseChunk; import org.apache.hertzbeat.ai.pojo.dto.SecurityData; @@ -57,6 +58,9 @@ public class ConversationServiceImpl implements ConversationService { @Autowired private ChatMessageDao messageDao; + @Autowired + private SopScheduleDao sopScheduleDao; + @Autowired private ChatClientProviderService chatClientProviderService; @@ -197,6 +201,8 @@ public class ConversationServiceImpl implements ConversationService { @Override @Transactional(rollbackFor = Exception.class) public void deleteConversation(Long conversationId) { + // 先删除关联计划,避免会话删除后定时任务继续执行并写入孤儿消息。 + sopScheduleDao.deleteByConversationId(conversationId); List<ChatMessage> messages = messageDao.findByConversationIdOrderByGmtCreateAsc(conversationId); if (!messages.isEmpty()) { messageDao.deleteAll(messages); diff --git a/hertzbeat-ai/src/test/java/org/apache/hertzbeat/ai/service/impl/ConversationServiceImplTest.java b/hertzbeat-ai/src/test/java/org/apache/hertzbeat/ai/service/impl/ConversationServiceImplTest.java index ce5f5bf3ef..ff38cb26ab 100644 --- a/hertzbeat-ai/src/test/java/org/apache/hertzbeat/ai/service/impl/ConversationServiceImplTest.java +++ b/hertzbeat-ai/src/test/java/org/apache/hertzbeat/ai/service/impl/ConversationServiceImplTest.java @@ -20,6 +20,7 @@ package org.apache.hertzbeat.ai.service.impl; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -30,6 +31,7 @@ import java.util.Optional; import java.util.concurrent.atomic.AtomicLong; import org.apache.hertzbeat.ai.dao.ChatConversationDao; import org.apache.hertzbeat.ai.dao.ChatMessageDao; +import org.apache.hertzbeat.ai.dao.SopScheduleDao; import org.apache.hertzbeat.ai.pojo.dto.ChatRequestContext; import org.apache.hertzbeat.ai.pojo.dto.ChatResponseChunk; import org.apache.hertzbeat.ai.service.ChatClientProviderService; @@ -40,6 +42,7 @@ import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.ArgumentCaptor; import org.mockito.InjectMocks; +import org.mockito.InOrder; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.http.codec.ServerSentEvent; @@ -59,6 +62,9 @@ class ConversationServiceImplTest { @Mock private ChatMessageDao messageDao; + @Mock + private SopScheduleDao sopScheduleDao; + @Mock private ChatClientProviderService chatClientProviderService; @@ -116,4 +122,26 @@ class ConversationServiceImplTest { assertEquals(history, contextCaptor.getValue().getConversationHistory()); assertEquals(subject, contextCaptor.getValue().getSubject()); } + + /** + * 删除会话时必须先清理关联计划,避免定时任务继续向已删除的会话推送消息。 + */ + @Test + void deleteConversationShouldRemoveSchedulesMessagesAndConversationInOrder() { + ChatMessage message = ChatMessage.builder() + .id(11L) + .conversationId(CONVERSATION_ID) + .role("user") + .content("待删除消息") + .build(); + when(messageDao.findByConversationIdOrderByGmtCreateAsc(CONVERSATION_ID)) + .thenReturn(List.of(message)); + + conversationService.deleteConversation(CONVERSATION_ID); + + InOrder deletionOrder = inOrder(sopScheduleDao, messageDao, conversationDao); + deletionOrder.verify(sopScheduleDao).deleteByConversationId(CONVERSATION_ID); + deletionOrder.verify(messageDao).deleteAll(List.of(message)); + deletionOrder.verify(conversationDao).deleteById(CONVERSATION_ID); + } } --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
