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]

Reply via email to