feat(condition): CONDITION 判断方式二选一——EXPRESSION 内置 Aviator 表达式(沙箱)+ SERVICE 原口径;JudgeBody 补 submitterId
- ExpressionEvaluator:Aviator 5.4.3 沙箱(FEATURE_SET 只留 If、ALLOWED_CLASS_SET 空=禁类访问/反射)、编译缓存、 顶层变量缺失抛错挂起(Aviator 缺失变量按 nil 且 nil 视作最小值,<= 兜底出口会静默放行——宁挂起不误放行) - ConditionRouteService.decide 分流:EXPRESSION 按出边顺序取首个 true(逐边结果摘要落 raw_response), 全 false/异常挂起沿用 SERVICE 纪律(route_log outlet=NULL + EXPRESSION 常量 + 告警 + 管理端重跑) - DefValidator 发布期分层校验:EXPRESSION 出口缺条件/语法错/违禁表达式硬拦;表单变量放行(运行时核对); 内置变量疑似拼错 warn;judgeMode 非法值拦 - /admin/router/eval 调试端点(同一求值核心,不落库不走流程) - 单测 22 新增 + 全量 170 绿;E2E 18/18(发布/分支选路/挂起留痕/重跑/调试)见 local-debug/four-topics-a-e2e.py
This commit is contained in:
@@ -42,6 +42,9 @@ public class ConditionRouteService {
|
||||
*/
|
||||
public String decide(FlwInstance instance, FlowDefModel model, FlowDefModel.Node node) {
|
||||
List<String> outlets = outletNames(model, node);
|
||||
if (node.expressionJudge()) {
|
||||
return decideByExpression(instance, model, node, outlets);
|
||||
}
|
||||
FlwRouter router = routerRepository.findByRouterKey(node.routerKey).orElse(null);
|
||||
if (router == null || router.getStatus() == null || router.getStatus() != 1) {
|
||||
log.error("[flow-center] 路由判断失败:routerKey={} 未注册或已停用(挂起):instance={} node={}",
|
||||
@@ -50,7 +53,8 @@ public class ConditionRouteService {
|
||||
}
|
||||
RouteJudgeClient.JudgeBody body = new RouteJudgeClient.JudgeBody(
|
||||
instance.getSchId(), instance.getId(), instance.getVersion(),
|
||||
instance.getBizType(), instance.getBizId(), node.id, node.name,
|
||||
instance.getBizType(), instance.getBizId(), instance.getSubmitterId(),
|
||||
node.id, node.name,
|
||||
node.routerKey, outlets, parseVariables(instance.getFormDataJson()));
|
||||
try {
|
||||
RouteJudgeClient.JudgeResult result = judgeClient.call(router, body);
|
||||
@@ -60,7 +64,7 @@ public class ConditionRouteService {
|
||||
return persistFailure(instance, node, outlets,
|
||||
"返回出口未命中 outlets:" + result.outlet + ";raw=" + result.rawResponse);
|
||||
}
|
||||
persist(instance, node, result.outlet, result.rawResponse);
|
||||
persist(instance, node, node.routerKey, result.outlet, result.rawResponse);
|
||||
log.info("[flow-center] 路由判断命中:instance={} node={} router={} outlet={}",
|
||||
instance.getId(), node.id, node.routerKey, result.outlet);
|
||||
return result.outlet;
|
||||
@@ -71,6 +75,54 @@ public class ConditionRouteService {
|
||||
}
|
||||
}
|
||||
|
||||
/** EXPRESSION 模式留痕的 router_key 快照(真实注册键不适用;列 NOT NULL) */
|
||||
static final String EXPRESSION_ROUTER_KEY = "EXPRESSION";
|
||||
|
||||
/**
|
||||
* EXPRESSION 模式(2026-10-10 四议题):按出边定义顺序对 condition 求值,首个 true 的出口名
|
||||
* 即结果;逐边结果摘要落 raw_response。全 false / 求值异常 → 挂起,沿用 SERVICE 模式纪律
|
||||
* (留痕 outlet=NULL + 告警 + 管理端重跑),不配默认出口。
|
||||
*/
|
||||
private String decideByExpression(FlwInstance instance, FlowDefModel model, FlowDefModel.Node node,
|
||||
List<String> outlets) {
|
||||
Map<String, Object> env = builtinEnv(instance, node, parseVariables(instance.getFormDataJson()));
|
||||
StringBuilder trace = new StringBuilder("EXPRESSION judge: ");
|
||||
try {
|
||||
for (FlowDefModel.Edge e : model.outEdges(node.id)) {
|
||||
Object result = ExpressionEvaluator.evaluate(e.condition, env);
|
||||
trace.append("[").append(e.name).append("] ").append(e.condition)
|
||||
.append(" => ").append(result).append("; ");
|
||||
if (Boolean.TRUE.equals(result)) {
|
||||
int attempt = persist(instance, node, EXPRESSION_ROUTER_KEY, e.name, trace.toString());
|
||||
log.info("[flow-center] 表达式判断命中:instance={} node={} outlet={} attempt={}",
|
||||
instance.getId(), node.id, e.name, attempt);
|
||||
return e.name;
|
||||
}
|
||||
}
|
||||
log.error("[flow-center] 表达式全部未命中(挂起):instance={} node={} outlets={} trace={}",
|
||||
instance.getId(), node.id, outlets, trace);
|
||||
return persistFailure(instance, node, outlets, "表达式全部未命中:" + trace);
|
||||
} catch (Exception e) {
|
||||
log.error("[flow-center] 表达式求值异常(挂起):instance={} node={} {}",
|
||||
instance.getId(), node.id, e.toString());
|
||||
return persistFailure(instance, node, outlets, "表达式求值异常:" + e + ";" + trace);
|
||||
}
|
||||
}
|
||||
|
||||
/** 内置变量注入(EXPRESSION 求值 env;SERVICE 模式的 JudgeBody 同名字段一一对应) */
|
||||
static Map<String, Object> builtinEnv(FlwInstance instance, FlowDefModel.Node node,
|
||||
Map<String, Object> variables) {
|
||||
variables.put("schId", instance.getSchId());
|
||||
variables.put("instanceId", instance.getId());
|
||||
variables.put("instanceVersion", instance.getVersion());
|
||||
variables.put("bizType", instance.getBizType());
|
||||
variables.put("bizId", instance.getBizId());
|
||||
variables.put("nodeId", node.id);
|
||||
variables.put("nodeName", node.name);
|
||||
variables.put("submitterId", instance.getSubmitterId());
|
||||
return variables;
|
||||
}
|
||||
|
||||
/** CONDITION 出边名即判断契约的 outlets(发布期已保证非空唯一) */
|
||||
private static List<String> outletNames(FlowDefModel model, FlowDefModel.Node node) {
|
||||
List<String> names = new ArrayList<>();
|
||||
@@ -97,19 +149,21 @@ public class ConditionRouteService {
|
||||
|
||||
private String persistFailure(FlwInstance instance, FlowDefModel.Node node, List<String> outlets,
|
||||
String error) {
|
||||
int attempt = persist(instance, node, null, truncate(error));
|
||||
int attempt = persist(instance, node, node.expressionJudge() ? EXPRESSION_ROUTER_KEY : node.routerKey,
|
||||
null, truncate(error));
|
||||
alertSuspended(instance, node, outlets, error, attempt);
|
||||
return null;
|
||||
}
|
||||
|
||||
/** 落一行留痕(REQUIRES_NEW:外部调用已真实发生,不随外层回滚),返回本轮 attempt(告警 msgNo 用) */
|
||||
private int persist(FlwInstance instance, FlowDefModel.Node node, String outlet, String raw) {
|
||||
private int persist(FlwInstance instance, FlowDefModel.Node node, String routerKeyLabel,
|
||||
String outlet, String raw) {
|
||||
FlwRouteLog logRow = new FlwRouteLog();
|
||||
logRow.setSchId(instance.getSchId());
|
||||
logRow.setInstanceId(instance.getId());
|
||||
logRow.setNodeId(node.id);
|
||||
logRow.setNodeName(node.name);
|
||||
logRow.setRouterKey(node.routerKey);
|
||||
logRow.setRouterKey(routerKeyLabel);
|
||||
logRow.setOutlet(outlet);
|
||||
logRow.setRawResponse(raw);
|
||||
return routeLogStore.append(logRow).getAttempt();
|
||||
|
||||
Reference in New Issue
Block a user