test: 补充流水标签执行日志
This commit is contained in:
@@ -24,10 +24,12 @@ import java.util.Date;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 流水标签服务实现
|
* 流水标签服务实现
|
||||||
*/
|
*/
|
||||||
|
@Slf4j
|
||||||
@Service
|
@Service
|
||||||
public class CcdiBankTagServiceImpl implements ICcdiBankTagService {
|
public class CcdiBankTagServiceImpl implements ICcdiBankTagService {
|
||||||
|
|
||||||
@@ -85,16 +87,23 @@ public class CcdiBankTagServiceImpl implements ICcdiBankTagService {
|
|||||||
* @param triggerType 触发方式
|
* @param triggerType 触发方式
|
||||||
*/
|
*/
|
||||||
public Long rebuildProject(Long projectId, String modelCode, String operator, TriggerType triggerType) {
|
public Long rebuildProject(Long projectId, String modelCode, String operator, TriggerType triggerType) {
|
||||||
|
long taskStartTime = System.currentTimeMillis();
|
||||||
CcdiBankTagTask task = buildRunningTask(projectId, modelCode, operator, triggerType);
|
CcdiBankTagTask task = buildRunningTask(projectId, modelCode, operator, triggerType);
|
||||||
taskMapper.insertTask(task);
|
taskMapper.insertTask(task);
|
||||||
|
log.info("【流水标签】任务创建成功: taskId={}, projectId={}, modelCode={}, triggerType={}, operator={}",
|
||||||
|
task.getId(), projectId, modelCode, triggerType, operator);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
List<CcdiBankTagRule> rules = ruleMapper.selectEnabledRules(modelCode);
|
List<CcdiBankTagRule> rules = ruleMapper.selectEnabledRules(modelCode);
|
||||||
|
log.info("【流水标签】加载启用规则完成: taskId={}, projectId={}, modelCode={}, ruleCount={}",
|
||||||
|
task.getId(), projectId, modelCode, rules.size());
|
||||||
|
log.info("【流水标签】开始清理历史结果: taskId={}, projectId={}, modelCode={}",
|
||||||
|
task.getId(), projectId, modelCode);
|
||||||
resultMapper.deleteByProjectAndModel(projectId, modelCode);
|
resultMapper.deleteByProjectAndModel(projectId, modelCode);
|
||||||
|
|
||||||
List<CompletableFuture<List<CcdiBankTagResult>>> futures = rules.stream()
|
List<CompletableFuture<List<CcdiBankTagResult>>> futures = rules.stream()
|
||||||
.map(rule -> CompletableFuture.supplyAsync(
|
.map(rule -> CompletableFuture.supplyAsync(
|
||||||
() -> executeRule(projectId, rule, operator),
|
() -> executeRule(task.getId(), projectId, rule, operator),
|
||||||
tagRuleExecutor
|
tagRuleExecutor
|
||||||
))
|
))
|
||||||
.toList();
|
.toList();
|
||||||
@@ -105,6 +114,8 @@ public class CcdiBankTagServiceImpl implements ICcdiBankTagService {
|
|||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
if (!allResults.isEmpty()) {
|
if (!allResults.isEmpty()) {
|
||||||
|
log.info("【流水标签】批量写入标签结果: taskId={}, projectId={}, resultCount={}",
|
||||||
|
task.getId(), projectId, allResults.size());
|
||||||
resultMapper.insertBatch(allResults);
|
resultMapper.insertBatch(allResults);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,6 +128,9 @@ public class CcdiBankTagServiceImpl implements ICcdiBankTagService {
|
|||||||
task.setUpdateBy(operator);
|
task.setUpdateBy(operator);
|
||||||
task.setUpdateTime(new Date());
|
task.setUpdateTime(new Date());
|
||||||
taskMapper.updateTask(task);
|
taskMapper.updateTask(task);
|
||||||
|
log.info("【流水标签】任务执行成功: taskId={}, projectId={}, modelCode={}, triggerType={}, ruleCount={}, hitCount={}, costMs={}",
|
||||||
|
task.getId(), projectId, modelCode, triggerType, rules.size(), allResults.size(),
|
||||||
|
System.currentTimeMillis() - taskStartTime);
|
||||||
return task.getId();
|
return task.getId();
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
task.setStatus(STATUS_FAILED);
|
task.setStatus(STATUS_FAILED);
|
||||||
@@ -126,6 +140,8 @@ public class CcdiBankTagServiceImpl implements ICcdiBankTagService {
|
|||||||
task.setUpdateBy(operator);
|
task.setUpdateBy(operator);
|
||||||
task.setUpdateTime(new Date());
|
task.setUpdateTime(new Date());
|
||||||
taskMapper.updateTask(task);
|
taskMapper.updateTask(task);
|
||||||
|
log.error("【流水标签】任务执行失败: taskId={}, projectId={}, modelCode={}, triggerType={}, error={}",
|
||||||
|
task.getId(), projectId, modelCode, triggerType, ex.getMessage(), ex);
|
||||||
throw ex;
|
throw ex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -149,15 +165,35 @@ public class CcdiBankTagServiceImpl implements ICcdiBankTagService {
|
|||||||
return task;
|
return task;
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<CcdiBankTagResult> executeRule(Long projectId, CcdiBankTagRule rule, String operator) {
|
private List<CcdiBankTagResult> executeRule(Long taskId, Long projectId, CcdiBankTagRule rule, String operator) {
|
||||||
|
long startTime = System.currentTimeMillis();
|
||||||
|
log.info("【流水标签】规则开始执行: taskId={}, projectId={}, ruleCode={}, resultType={}",
|
||||||
|
taskId, projectId, rule.getRuleCode(), rule.getResultType());
|
||||||
BankTagRuleExecutionConfig config = configResolver.resolve(projectId, rule);
|
BankTagRuleExecutionConfig config = configResolver.resolve(projectId, rule);
|
||||||
|
log.debug("【流水标签】规则执行参数: taskId={}, ruleCode={}, thresholds={}",
|
||||||
|
taskId, rule.getRuleCode(), config.getThresholdValues());
|
||||||
if (RESULT_TYPE_STATEMENT.equals(rule.getResultType())) {
|
if (RESULT_TYPE_STATEMENT.equals(rule.getResultType())) {
|
||||||
List<BankTagStatementHitVO> hits = executeStatementRule(projectId, rule, config);
|
List<BankTagStatementHitVO> hits = executeStatementRule(projectId, rule, config);
|
||||||
return buildStatementResults(projectId, rule, hits, operator);
|
List<CcdiBankTagResult> results = buildStatementResults(projectId, rule, hits, operator);
|
||||||
|
logRuleCompletion(taskId, projectId, rule.getRuleCode(), results.size(), startTime);
|
||||||
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<BankTagObjectHitVO> hits = executeObjectRule(projectId, rule, config);
|
List<BankTagObjectHitVO> hits = executeObjectRule(projectId, rule, config);
|
||||||
return buildObjectResults(projectId, rule, hits, operator);
|
List<CcdiBankTagResult> results = buildObjectResults(projectId, rule, hits, operator);
|
||||||
|
logRuleCompletion(taskId, projectId, rule.getRuleCode(), results.size(), startTime);
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void logRuleCompletion(Long taskId, Long projectId, String ruleCode, int hitCount, long startTime) {
|
||||||
|
long costMs = System.currentTimeMillis() - startTime;
|
||||||
|
if (hitCount == 0) {
|
||||||
|
log.warn("【流水标签】规则无命中: taskId={}, projectId={}, ruleCode={}, costMs={}",
|
||||||
|
taskId, projectId, ruleCode, costMs);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
log.info("【流水标签】规则执行完成: taskId={}, projectId={}, ruleCode={}, hitCount={}, costMs={}",
|
||||||
|
taskId, projectId, ruleCode, hitCount, costMs);
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<BankTagStatementHitVO> executeStatementRule(Long projectId,
|
private List<BankTagStatementHitVO> executeStatementRule(Long projectId,
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
package com.ruoyi.ccdi.project.service.impl;
|
package com.ruoyi.ccdi.project.service.impl;
|
||||||
|
|
||||||
|
import ch.qos.logback.classic.Logger;
|
||||||
|
import ch.qos.logback.classic.spi.ILoggingEvent;
|
||||||
|
import ch.qos.logback.core.read.ListAppender;
|
||||||
import com.ruoyi.ccdi.project.domain.entity.CcdiBankTagRule;
|
import com.ruoyi.ccdi.project.domain.entity.CcdiBankTagRule;
|
||||||
import com.ruoyi.ccdi.project.domain.entity.CcdiBankTagTask;
|
import com.ruoyi.ccdi.project.domain.entity.CcdiBankTagTask;
|
||||||
import com.ruoyi.ccdi.project.domain.enums.TriggerType;
|
import com.ruoyi.ccdi.project.domain.enums.TriggerType;
|
||||||
@@ -15,13 +18,17 @@ import org.mockito.InOrder;
|
|||||||
import org.mockito.InjectMocks;
|
import org.mockito.InjectMocks;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.junit.jupiter.MockitoExtension;
|
import org.mockito.junit.jupiter.MockitoExtension;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.test.util.ReflectionTestUtils;
|
import org.springframework.test.util.ReflectionTestUtils;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
import static org.mockito.ArgumentMatchers.anyList;
|
import static org.mockito.ArgumentMatchers.anyList;
|
||||||
|
import static org.mockito.Mockito.doAnswer;
|
||||||
import static org.mockito.Mockito.inOrder;
|
import static org.mockito.Mockito.inOrder;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
@@ -81,4 +88,91 @@ class CcdiBankTagServiceImplTest {
|
|||||||
inOrder.verify(resultMapper).insertBatch(anyList());
|
inOrder.verify(resultMapper).insertBatch(anyList());
|
||||||
verify(taskMapper).insertTask(any(CcdiBankTagTask.class));
|
verify(taskMapper).insertTask(any(CcdiBankTagTask.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void rebuildProject_shouldLogTaskLifecycleAndRuleSummary() {
|
||||||
|
ReflectionTestUtils.setField(service, "tagRuleExecutor", (Executor) Runnable::run);
|
||||||
|
|
||||||
|
CcdiBankTagRule rule = new CcdiBankTagRule();
|
||||||
|
rule.setModelCode("LARGE_TRANSACTION");
|
||||||
|
rule.setModelName("大额交易");
|
||||||
|
rule.setRuleCode("HOUSE_OR_CAR_EXPENSE");
|
||||||
|
rule.setRuleName("房车消费支出交易");
|
||||||
|
rule.setResultType("STATEMENT");
|
||||||
|
|
||||||
|
BankTagRuleExecutionConfig config = new BankTagRuleExecutionConfig();
|
||||||
|
config.setProjectId(40L);
|
||||||
|
config.setRuleMeta(rule);
|
||||||
|
|
||||||
|
BankTagStatementHitVO hit = new BankTagStatementHitVO();
|
||||||
|
hit.setBankStatementId(10L);
|
||||||
|
hit.setGroupId(40);
|
||||||
|
hit.setLogId(40001);
|
||||||
|
hit.setReasonDetail("命中房车消费支出");
|
||||||
|
|
||||||
|
doAnswer(invocation -> {
|
||||||
|
CcdiBankTagTask task = invocation.getArgument(0);
|
||||||
|
task.setId(88L);
|
||||||
|
return 1;
|
||||||
|
}).when(taskMapper).insertTask(any(CcdiBankTagTask.class));
|
||||||
|
|
||||||
|
when(ruleMapper.selectEnabledRules(null)).thenReturn(List.of(rule));
|
||||||
|
when(configResolver.resolve(40L, rule)).thenReturn(config);
|
||||||
|
when(analysisMapper.selectHouseOrCarExpenseStatements(40L)).thenReturn(List.of(hit));
|
||||||
|
|
||||||
|
Logger logger = (Logger) LoggerFactory.getLogger(CcdiBankTagServiceImpl.class);
|
||||||
|
ListAppender<ILoggingEvent> logAppender = new ListAppender<>();
|
||||||
|
logAppender.start();
|
||||||
|
logger.addAppender(logAppender);
|
||||||
|
|
||||||
|
try {
|
||||||
|
service.rebuildProject(40L, null, "admin", TriggerType.MANUAL);
|
||||||
|
|
||||||
|
assertTrue(logAppender.list.stream().map(ILoggingEvent::getFormattedMessage)
|
||||||
|
.anyMatch(message -> message.contains("任务创建成功")
|
||||||
|
&& message.contains("taskId=88")
|
||||||
|
&& message.contains("projectId=40")));
|
||||||
|
assertTrue(logAppender.list.stream().map(ILoggingEvent::getFormattedMessage)
|
||||||
|
.anyMatch(message -> message.contains("规则执行完成")
|
||||||
|
&& message.contains("ruleCode=HOUSE_OR_CAR_EXPENSE")
|
||||||
|
&& message.contains("hitCount=1")));
|
||||||
|
} finally {
|
||||||
|
logger.detachAppender(logAppender);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void rebuildProject_shouldLogFailureSummaryWhenRuleExecutionFails() {
|
||||||
|
ReflectionTestUtils.setField(service, "tagRuleExecutor", (Executor) Runnable::run);
|
||||||
|
|
||||||
|
CcdiBankTagRule rule = new CcdiBankTagRule();
|
||||||
|
rule.setModelCode("LARGE_TRANSACTION");
|
||||||
|
rule.setRuleCode("HOUSE_OR_CAR_EXPENSE");
|
||||||
|
rule.setResultType("STATEMENT");
|
||||||
|
|
||||||
|
doAnswer(invocation -> {
|
||||||
|
CcdiBankTagTask task = invocation.getArgument(0);
|
||||||
|
task.setId(89L);
|
||||||
|
return 1;
|
||||||
|
}).when(taskMapper).insertTask(any(CcdiBankTagTask.class));
|
||||||
|
|
||||||
|
when(ruleMapper.selectEnabledRules(null)).thenReturn(List.of(rule));
|
||||||
|
when(configResolver.resolve(40L, rule)).thenThrow(new RuntimeException("threshold missing"));
|
||||||
|
|
||||||
|
Logger logger = (Logger) LoggerFactory.getLogger(CcdiBankTagServiceImpl.class);
|
||||||
|
ListAppender<ILoggingEvent> logAppender = new ListAppender<>();
|
||||||
|
logAppender.start();
|
||||||
|
logger.addAppender(logAppender);
|
||||||
|
|
||||||
|
try {
|
||||||
|
assertThrows(RuntimeException.class,
|
||||||
|
() -> service.rebuildProject(40L, null, "admin", TriggerType.MANUAL));
|
||||||
|
assertTrue(logAppender.list.stream().map(ILoggingEvent::getFormattedMessage)
|
||||||
|
.anyMatch(message -> message.contains("任务执行失败")
|
||||||
|
&& message.contains("taskId=89")
|
||||||
|
&& message.contains("threshold missing")));
|
||||||
|
} finally {
|
||||||
|
logger.detachAppender(logAppender);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user