feat: cancel running instances as CANCELLED without initiator checks

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
0264408
2026-09-16 09:47:58 +08:00
co-authored by Cursor
parent 30047f3612
commit 8bc628613d
11 changed files with 138 additions and 28 deletions
+1 -4
View File
@@ -15,15 +15,12 @@
- 审计 `ProcessEvent` / `queryHistory`;`OrdoEventListener`
- 任务转派 `reassign` / `TASK_REASSIGNED`
- 到期升级 `processDue` / `TASK_ESCALATED`
- 管理员/系统取消 `cancel` / `CANCELLED`
## 开发计划(确定要做)
下列能力已纳入计划,尚未实现。实现顺序可按依赖调整,但范围本身不从计划中拿掉。
### CANCELLED
目前终态只有 `APPROVED` / `REJECTED` / `WITHDRAWN`(撤回仅发起人)。计划增加管理员/系统取消语义 `CANCELLED`,与撤回区分。
### 定义不可变多版本
当前同 `id` 用 `replace` 整体替换;存在 `RUNNING` 实例时拒绝。计划改为定义不可变多版本:新版本不改写旧版本;运行中实例锁定发起时所用版本。
+12 -8
View File
@@ -12,7 +12,7 @@ Ordo 是嵌入宿主进程的审批引擎,入口是 `OrdoEngine`。
产品边界:不做业务表单、用户体系、多租户;不内置设计器 UI。业务字段放在 `ProcessContext`(不可变 `Map<String, Object>`)。当前也**没有** REST;HTTP 仍由宿主自建。计划中的可选 REST 与独立设计器见 [roadmap.md](roadmap.md)。
开发计划(尚未提供,见 [roadmap.md](roadmap.md)):`CANCELLED`、定义不可变多版本、MySQL 方言、可选 REST + 目录 SPI。
开发计划(尚未提供,见 [roadmap.md](roadmap.md)):定义不可变多版本、MySQL 方言、可选 REST + 目录 SPI。
## 2. 模块与接入
@@ -185,6 +185,7 @@ start → RUNNING
approve / 路由结束 → APPROVED
reject(步被否决)→ REJECTED
withdraw(仅发起人)→ WITHDRAWN,剩余 PENDING 任务 → SKIPPED
cancel(任意非空 actor)→ CANCELLED,剩余 PENDING 任务 → SKIPPED
```
```java
@@ -197,6 +198,7 @@ ordo.approve(pending.get(0).id(), "diana", "ok");
ordo.reject(taskId, "maria", "额度不足");
ordo.withdraw(instance.id(), "alice", "计划有变");
ordo.cancel(instance.id(), "admin", "政策变更");
```
`start` 的 `initiator`、办理人 `actor` 均不可空白。
@@ -208,14 +210,15 @@ ordo.withdraw(instance.id(), "alice", "计划有变");
- `processDue(limit)`:认领 `dueAt <= now` 的 PENDING 任务(`limit > 0`),按步上 `due.then` 执行:`reassign` 换办理人(`to` 走 `AssigneeResolver`)、`notify` 可选 `ActionHandler`、`goto` 跳过当前步 PENDING 并进入 `to` 步骤(`to` 必须是步骤 id)。每种策略对一张任务最多成功一次(清空 `dueAt`)。引擎无后台线程;Spring 下 `ordo.due.poll-ms > 0` 才轮询。
- 任务非 `PENDING`:`TaskAlreadyCompletedException`。
- `withdraw`:仅 `initiator`,否则 `UnauthorizedInstanceOperationException`;实例非 `RUNNING`:`InstanceAlreadyCompletedException`。
- `cancel`:`actor` 非空即可,**不校验**是否发起人;实例须为 `RUNNING`,否则 `InstanceAlreadyCompletedException`。谁能调用由宿主决定。
没有管理员代批、没有系统取消。
没有管理员代批。
### 4.3 状态
实例 `ProcessStatus`:`RUNNING`、`APPROVED`、`REJECTED`、`WITHDRAWN`。
实例 `ProcessStatus`:`RUNNING`、`APPROVED`、`REJECTED`、`WITHDRAWN`、`CANCELLED`。
任务 `TaskStatus`:`PENDING`、`APPROVED`、`REJECTED`、`SKIPPED`(同一步其它候选人已决定结果,或实例被撤回)。
任务 `TaskStatus`:`PENDING`、`APPROVED`、`REJECTED`、`SKIPPED`(同一步其它候选人已决定结果,或实例被撤回/取消)。
`ApprovalTask.action`(`TaskAction`)仍表示**该任务**上的办理人/意见/时间;实例级时间线用 `ProcessEvent`,不要靠拼任务 action 还原流程史。
@@ -278,7 +281,7 @@ public class MailActions implements ActionHandler {
`ProcessEventType`:
- `INSTANCE_STARTED` / `INSTANCE_APPROVED` / `INSTANCE_REJECTED` / `INSTANCE_WITHDRAWN`
- `INSTANCE_STARTED` / `INSTANCE_APPROVED` / `INSTANCE_REJECTED` / `INSTANCE_WITHDRAWN` / `INSTANCE_CANCELLED`
- `TASK_CREATED` / `TASK_APPROVED` / `TASK_REJECTED` / `TASK_SKIPPED` / `TASK_REASSIGNED` / `TASK_ESCALATED`
- `ACTION_SUCCEEDED` / `ACTION_FAILED`
@@ -318,6 +321,7 @@ ACTION 成功事件发生在提交之后,因此排在同轮事务内写入的
| `reassign` | 当前办理人把 PENDING 任务转给他人 |
| `processDue` | 认领并处理已到期 PENDING 任务 |
| `withdraw` | 发起人撤回 |
| `cancel` | 管理员/系统取消(引擎不鉴权角色) |
| `find*` | 按 id / 待办索引读取 |
| `queryTasks` / `queryInstances` / `queryDefinitions` | 分页列表 |
| `queryHistory` / `queryActionExecutions` | 实例审计与 ACTION 记录 |
@@ -331,8 +335,8 @@ ACTION 成功事件发生在提交之后,因此排在同轮事务内写入的
| `DefinitionAlreadyExistsException` | `register` 撞 id |
| `DefinitionNotFoundException` | `start` 等找不到定义 |
| `DefinitionInUseException` | `replace` 时仍有 RUNNING 实例 |
| `InstanceNotFoundException` | 撤回等找不到实例 |
| `InstanceAlreadyCompletedException` | 对非 RUNNING 实例完成/撤回 |
| `InstanceNotFoundException` | 撤回/取消等找不到实例 |
| `InstanceAlreadyCompletedException` | 对非 RUNNING 实例完成/撤回/取消 |
| `TaskNotFoundException` | 任务 id 不存在 |
| `TaskAlreadyCompletedException` | 重复办理或已被 SKIPPED |
| `UnauthorizedTaskOperationException` | actor ≠ 当前 assignee(approve / reject / reassign) |
@@ -349,6 +353,6 @@ Flyway 脚本在 `ordo-storage-jdbc` 的 `db/migration`(V1–V6)。表包括
## 13. 未提供能力
开发计划中(见 [roadmap.md](roadmap.md)):`CANCELLED`、定义不可变多版本、MySQL 方言、可选 REST + 目录 SPI。独立设计器不进本仓库,等 REST、目录与多版本定义之后再做。
开发计划中(见 [roadmap.md](roadmap.md)):定义不可变多版本、MySQL 方言、可选 REST + 目录 SPI。独立设计器不进本仓库,等 REST、目录与多版本定义之后再做。
暂不在计划中:多租户、设计器 UI。当前 REST 由宿主自建。