feat: evaluate built-in routing predicates and parameterized host conditions
Store transition when as JSON instead of a lookup key so designers can compose closed-set logic while hosts still supply complex refs with args. Match conditional edges before the unconditional default. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -365,7 +365,7 @@ paths:
|
||||
get:
|
||||
responses:
|
||||
'200':
|
||||
description: conditionKey catalog
|
||||
description: host condition catalog (ref + optional params)
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
@@ -458,6 +458,18 @@ components:
|
||||
type: string
|
||||
label:
|
||||
type: string
|
||||
params:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
type:
|
||||
type: string
|
||||
enum: [number, string, boolean]
|
||||
label:
|
||||
type: string
|
||||
ProcessDefinitionDocument:
|
||||
type: object
|
||||
required: [id, name, steps, transitions]
|
||||
@@ -485,6 +497,7 @@ components:
|
||||
type: string
|
||||
nullable: true
|
||||
when:
|
||||
type: string
|
||||
type: object
|
||||
additionalProperties: true
|
||||
priority:
|
||||
type: integer
|
||||
|
||||
+1
-1
@@ -9,7 +9,7 @@
|
||||
- ANY/ALL 会签/或签
|
||||
- JDBC 存储(PostgreSQL / MySQL)+ 按方言 Flyway 基线
|
||||
- 定义不可变多版本:`publish`;实例锁定 `definitionVersion`
|
||||
- 条件路由 `StepTransition` + `RoutingCondition`
|
||||
- 条件路由 `StepTransition`:内置谓词 AST 或宿主 `RoutingCondition`(`ref` + `args`)
|
||||
- ACTION + `ActionHandler`;执行记录持久化
|
||||
- 发起人撤回 `WITHDRAWN`
|
||||
- 分页查询:任务 / 实例 / 定义
|
||||
|
||||
+10
-11
@@ -76,7 +76,7 @@ ordo:
|
||||
| Bean | 默认 |
|
||||
|---|---|
|
||||
| `AssigneeResolver` | 候选人字符串即办理人 |
|
||||
| `RoutingCondition` | 始终匹配(无条件边) |
|
||||
| `RoutingCondition` | `ref` 边默认恒 true;无 `when` 的边不经过该 Bean |
|
||||
| `ActionHandler` | 空操作 |
|
||||
| `OrdoEventListener` | 可有多个,提交后按 Spring 顺序调用 |
|
||||
| `OrdoCatalog` | 空列表(仅 REST 打开时装配) |
|
||||
@@ -144,8 +144,8 @@ new ProcessDefinition("leave-request-routed", "Leave request",
|
||||
),
|
||||
List.of(
|
||||
StepTransition.always("notify-submitted", "manager"),
|
||||
StepTransition.when("manager", "hr", "days-gt-3", 0),
|
||||
StepTransition.when("manager", "notify-approved", null, 1),
|
||||
StepTransition.when("manager", "hr", RoutingPredicate.gt("days", 3), 0),
|
||||
new StepTransition("manager", "notify-approved", null, 1),
|
||||
StepTransition.always("hr", "notify-approved"),
|
||||
StepTransition.end("notify-approved")
|
||||
));
|
||||
@@ -192,7 +192,7 @@ new ProcessDefinition("leave-request-routed", "Leave request",
|
||||
],
|
||||
"transitions": [
|
||||
{ "from": "notify-submitted", "to": "manager" },
|
||||
{ "from": "manager", "to": "hr", "when": "days-gt-3", "priority": 0 },
|
||||
{ "from": "manager", "to": "hr", "when": { "gt": ["days", 3] }, "priority": 0 },
|
||||
{ "from": "manager", "to": "notify-approved", "priority": 1 },
|
||||
{ "from": "hr", "to": "notify-approved" },
|
||||
{ "from": "notify-approved", "to": null }
|
||||
@@ -209,7 +209,7 @@ new ProcessDefinition("leave-request-routed", "Leave request",
|
||||
| `candidates` / `policy` | 仅审批步。`policy` 默认 `ANY`。审批步至少一名候选人,禁止重复。 |
|
||||
| `action` | 仅 ACTION 步,对应 `ActionHandler.execute` 的 key。审批步禁止带 `action`。 |
|
||||
| `due` | 仅审批步。可选。`after` 为 ISO-8601 时长;`then` 为 `reassign` / `notify` / `goto`。进入该步时任务 `dueAt = now + after`。 |
|
||||
| `from` / `to` / `when` / `priority` | `to` 为 `null` 或 JSON `null` 表示结束。`when` 空则无条件。`priority` 默认 0,**越小越先匹配**。 |
|
||||
| `from` / `to` / `when` / `priority` | `to` 为 `null` 或 JSON `null` 表示结束。`when` 省略则无条件(else)。`priority` 默认 0,**仅在同类边之间越小越先匹配**(条件边一组,无条件边一组)。 |
|
||||
|
||||
## 4. 实例与任务
|
||||
|
||||
@@ -274,18 +274,17 @@ ordo.cancel(instance.id(), "admin", "政策变更");
|
||||
|
||||
## 6. 条件路由
|
||||
|
||||
离开当前步时,取出全部 `from = 当前步` 的边,按 `priority` 升序。第一条满足下列条件的边生效:
|
||||
离开当前步时,取出全部 `from = 当前步` 的边。**先**按 `priority` 升序匹配带 `when` 的边(谓词为真,或 `ref` 且 `routingCondition.matches` 为真);都未命中再按 `priority` 走无 `when` 的边(else)。无条件边不再与条件边抢数字顺序。
|
||||
|
||||
- `conditionKey` 为空,或
|
||||
- `routingCondition.matches(conditionKey, instance.context()) == true`
|
||||
`when` 必须是 JSON **对象**,不能再写字符串 key。谓词闭集:`eq/ne/gt/gte/lt/lte`、`in`、`and/or/not`(深度 ≤ 8、叶子 ≤ 32)。宿主复杂逻辑用 `ref` + `args`,例如 `{ "ref": "amountGt", "args": { "threshold": 50000 } }`。
|
||||
|
||||
没有匹配边:`NoRouteFoundException`,**整次 approve/start 事务回滚**(JDBC 下任务/实例都不会半更新)。
|
||||
|
||||
无条件边通常作为默认分支,`priority` 应大于带 `when` 的边。
|
||||
无条件边是默认分支;`priority` 只在同类边之间比较(多条条件边之间,或多条无条件边之间)。
|
||||
|
||||
`RoutingCondition` 只看到 `ProcessContext`,看不到任务意见,也**没有**流程定义 id。上下文在 `start` 时写入,运行中引擎**不会**改 context。
|
||||
`RoutingCondition` 只看到 `ProcessContext` 与 `args`,看不到任务意见,也没有流程定义 id。上下文在 `start` 时写入,运行中引擎不会改 context。未知 `ref` 由宿主返回 `false`,该边不匹配。
|
||||
|
||||
引擎只注入**一个** `RoutingCondition`(与 `ActionHandler` 相同)。Spring 下多个该类型 Bean 会冲突。宿主用一个门面按 `conditionKey` 分发到多套规则;不同流程靠 key 约定隔离(例如 `leave.days-gt-3`),不要指望引擎按定义拆 bean。
|
||||
引擎只注入**一个** `RoutingCondition`。Spring 下多个该类型 Bean 会冲突。宿主用一个门面按 `ref` 分发;不要指望引擎按定义拆 bean。
|
||||
|
||||
## 7. ACTION 步骤
|
||||
|
||||
|
||||
Reference in New Issue
Block a user