feat: 增强多实例分布式部署兼容
- 增加定时任务分布式锁并覆盖 chatlog、文档导入和 Agent HITL 过期扫描 - 增强 Redis MQ 多实例 consumer 标识、pending reclaim 和单条处理能力 - 增加文档导入状态 Redis 广播和 Agent HITL 跨节点路由确认
This commit is contained in:
@@ -0,0 +1,97 @@
|
||||
package tech.easyflow.ai.documentimport.task;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.mockito.ArgumentMatchers;
|
||||
import org.mockito.Mockito;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
||||
import tech.easyflow.ai.entity.Document;
|
||||
import tech.easyflow.ai.mapper.DocumentMapper;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.math.BigInteger;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
/**
|
||||
* {@link DocumentImportTaskStatusStreamService} 回归测试。
|
||||
*/
|
||||
public class DocumentImportTaskStatusStreamServiceTest {
|
||||
|
||||
/**
|
||||
* 验证文档状态变更会向 Redis 广播文档 ID。
|
||||
*
|
||||
* @throws Exception 反射注入异常
|
||||
*/
|
||||
@Test
|
||||
public void publishAfterCommitShouldBroadcastDocumentId() throws Exception {
|
||||
StringRedisTemplate redisTemplate = Mockito.mock(StringRedisTemplate.class);
|
||||
DocumentImportTaskStatusStreamService service = new DocumentImportTaskStatusStreamService();
|
||||
setField(service, "documentMapper", mockDocumentMapper());
|
||||
setField(service, "sseThreadPool", directExecutor());
|
||||
setField(service, "stringRedisTemplate", redisTemplate);
|
||||
setField(service, "statusBroadcastProperties", statusBroadcastProperties());
|
||||
|
||||
service.publishAfterCommit(BigInteger.valueOf(101));
|
||||
|
||||
Mockito.verify(redisTemplate).convertAndSend("easyflow:document-import:test-status", "101");
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证收到 Redis 广播后会重新查询文档状态。
|
||||
*
|
||||
* @throws Exception 反射注入异常
|
||||
*/
|
||||
@Test
|
||||
public void publishLocalShouldReloadDocumentStatus() throws Exception {
|
||||
AtomicReference<BigInteger> selectedIdRef = new AtomicReference<BigInteger>();
|
||||
DocumentImportTaskStatusStreamService service = new DocumentImportTaskStatusStreamService();
|
||||
setField(service, "documentMapper", mockDocumentMapper(selectedIdRef));
|
||||
setField(service, "sseThreadPool", directExecutor());
|
||||
setField(service, "stringRedisTemplate", Mockito.mock(StringRedisTemplate.class));
|
||||
setField(service, "statusBroadcastProperties", statusBroadcastProperties());
|
||||
|
||||
service.publishLocal(BigInteger.valueOf(202));
|
||||
|
||||
Assert.assertEquals(BigInteger.valueOf(202), selectedIdRef.get());
|
||||
}
|
||||
|
||||
private DocumentImportStatusBroadcastProperties statusBroadcastProperties() {
|
||||
DocumentImportStatusBroadcastProperties properties = new DocumentImportStatusBroadcastProperties();
|
||||
properties.setStatusBroadcastChannel("easyflow:document-import:test-status");
|
||||
return properties;
|
||||
}
|
||||
|
||||
private DocumentMapper mockDocumentMapper() {
|
||||
return mockDocumentMapper(new AtomicReference<BigInteger>());
|
||||
}
|
||||
|
||||
private DocumentMapper mockDocumentMapper(AtomicReference<BigInteger> selectedIdRef) {
|
||||
DocumentMapper mapper = Mockito.mock(DocumentMapper.class);
|
||||
Mockito.when(mapper.selectOneById(ArgumentMatchers.any())).thenAnswer(invocation -> {
|
||||
Object id = invocation.getArgument(0);
|
||||
selectedIdRef.set((BigInteger) id);
|
||||
Document document = new Document();
|
||||
document.setId((BigInteger) id);
|
||||
document.setCollectionId(BigInteger.valueOf(1));
|
||||
return document;
|
||||
});
|
||||
return mapper;
|
||||
}
|
||||
|
||||
private ThreadPoolTaskExecutor directExecutor() {
|
||||
ThreadPoolTaskExecutor executor = Mockito.mock(ThreadPoolTaskExecutor.class);
|
||||
Mockito.doAnswer(invocation -> {
|
||||
Runnable runnable = invocation.getArgument(0);
|
||||
runnable.run();
|
||||
return null;
|
||||
}).when(executor).execute(ArgumentMatchers.any(Runnable.class));
|
||||
return executor;
|
||||
}
|
||||
|
||||
private void setField(Object target, String fieldName, Object value) throws Exception {
|
||||
Field field = DocumentImportTaskStatusStreamService.class.getDeclaredField(fieldName);
|
||||
field.setAccessible(true);
|
||||
field.set(target, value);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user