chore: target Java 17 and document usage plus roadmap
Lower the compiler baseline to 17, rename listDefinitions to queryDefinitions, and align README/usage/roadmap with planned vs out-of-scope work. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+38
-33
@@ -1,45 +1,50 @@
|
||||
# Ordo Roadmap
|
||||
|
||||
记录当前已完成能力之后,后续要做的开发计划。按优先级分组,供后续排期/立项参考。
|
||||
本文档是后续开发计划。「开发计划」中的项会做。「暂不在计划中」的项在另有决定前不做。除此之外仍可能立项其他新特性。
|
||||
|
||||
## 已完成(背景,非本文档重点)
|
||||
对外行为落地后同步 [usage.md](usage.md)。
|
||||
|
||||
- ANY/ALL 多候选人会签/或签(见 `/memories/repo/any-all-multi-approval.md`)
|
||||
- JDBC 存储模块 + Flyway 迁移(V1~V4)
|
||||
## 已完成
|
||||
|
||||
- ANY/ALL 会签/或签
|
||||
- JDBC 存储(PostgreSQL)+ Flyway V1–V5
|
||||
- 条件路由 `StepTransition` + `RoutingCondition`
|
||||
- ACTION 步骤 + `ActionHandler`
|
||||
- 流程撤回(`WITHDRAWN`)
|
||||
- **任务/实例/流程定义分页过滤查询 API**(2026-09-15 完成):`ApprovalTaskRepository.query`、
|
||||
`ProcessInstanceRepository.query`、`ProcessDefinitionRepository.findAll` + `OrdoEngine` 对应的
|
||||
`queryTasks`/`queryInstances`/`listDefinitions`,均支持 `PageRequest`/`Page` 分页与按
|
||||
assignee/instanceId/definitionId/status/initiator/时间范围过滤,默认按时间降序(最新优先)。
|
||||
- ACTION + `ActionHandler`;执行记录持久化
|
||||
- 发起人撤回 `WITHDRAWN`
|
||||
- 分页查询:任务 / 实例 / 定义
|
||||
- 审计 `ProcessEvent` / `queryHistory`;`OrdoEventListener`
|
||||
|
||||
## P0 — 审计与扩展点
|
||||
## 开发计划(确定要做)
|
||||
|
||||
- [x] **独立历史/审计事件模型**:现在历史只能靠 `ApprovalTask.action` 字段拼凑,没有独立的流程事件表
|
||||
(谁在何时对哪个实例做了什么)。建议新增 `ProcessEvent`/`ProcessHistoryRepository`。
|
||||
- [x] **状态变更事件监听器**:`OrdoEngine` 目前没有任何 listener/hook,无法在任务创建、审批、实例完成时
|
||||
被外部感知(做通知、写审计日志等)。可加 `OrdoEventListener` 扩展点,风格与 `AssigneeResolver`/
|
||||
`RoutingCondition` 一致。
|
||||
- [x] **ACTION 步骤执行记录持久化**:目前 `ActionHandler` 执行结果只在宿主内存里记(如 rhizome 的
|
||||
`LeaveActionHandler`),重启即丢失,且失败只打日志不影响流程状态,需要设计重试/失败处理策略。
|
||||
下列能力已纳入计划,尚未实现。实现顺序可按依赖调整,但范围本身不从计划中拿掉。
|
||||
|
||||
## P1 — 任务生命周期完善
|
||||
### 任务转派
|
||||
|
||||
- [ ] **任务委托/转派(delegate/reassign)**:任务创建后 assignee 不可变,无法转交他人处理。
|
||||
- [ ] **超时/升级(SLA/escalation)**:无到期时间、定时器、自动升级机制。
|
||||
- [ ] **流程实例取消 vs 撤回**:目前只有 `WITHDRAWN`(仅发起人可操作),没有管理员/系统层面的
|
||||
`CANCELLED` 语义。
|
||||
任务创建后当前 `assignee` 不可变。计划提供委托/转派(delegate/reassign),把待办转给他人办理,并写入审计。
|
||||
|
||||
## P2 — 架构级演进(范围较大,放在后面)
|
||||
### 到期升级
|
||||
|
||||
- [ ] **流程定义版本化**:目前同 id 直接整体替换(`replace`),建议演进为不可变多版本 + 运行中实例
|
||||
锁定所用版本。
|
||||
- [ ] **多租户支持**:数据模型无 tenant 隔离字段。
|
||||
- [ ] **JDBC 多方言支持**:目前 DDL/实现明显偏向 PostgreSQL(唯一键冲突处理等),无 MySQL/Testcontainers
|
||||
测试,若要支持更多数据库需要抽象 dialect 层。
|
||||
- [ ] **通用 REST Starter**:现在 REST 层完全是 rhizome 自己写的 demo,可考虑提供一个可选的
|
||||
`ordo-spring-boot-starter-web` 暴露标准 REST 接口。
|
||||
- [ ] **表单/UI schema、子流程、并行 fork-join**:属于更大的引擎能力扩展,优先级最低,等基础能力稳定后
|
||||
再评估是否需要。
|
||||
目前无到期时间与定时器。计划支持 SLA/超时:到期后升级(改办理人、通知或进入指定步骤),即「到期升级」。
|
||||
|
||||
### CANCELLED
|
||||
|
||||
目前终态只有 `APPROVED` / `REJECTED` / `WITHDRAWN`(撤回仅发起人)。计划增加管理员/系统取消语义 `CANCELLED`,与撤回区分。
|
||||
|
||||
### 定义不可变多版本
|
||||
|
||||
当前同 `id` 用 `replace` 整体替换;存在 `RUNNING` 实例时拒绝。计划改为定义不可变多版本:新版本不改写旧版本;运行中实例锁定发起时所用版本。
|
||||
|
||||
### MySQL 方言
|
||||
|
||||
当前 JDBC DDL/冲突处理面向 PostgreSQL。计划增加 MySQL 方言(及对应测试),通过 dialect 层扩展,而不是只支持一种库。
|
||||
|
||||
## 暂不在计划中
|
||||
|
||||
- **多租户**(数据模型无 tenant 隔离)
|
||||
- **官方 REST Starter**(不提供 `ordo-spring-boot-starter-web`;REST 由宿主自建)
|
||||
|
||||
## 后续新特性
|
||||
|
||||
上表「确定要做」之外,仍可能立项其他能力(例如表单/UI schema、子流程、并行 fork-join)。**多租户与官方 REST 在另有明确决定前不进入计划。**
|
||||
|
||||
新特性立项时写入「开发计划」对应小节;完成后移到「已完成」,并更新 [usage.md](usage.md)。
|
||||
|
||||
+344
@@ -0,0 +1,344 @@
|
||||
# Ordo 使用说明
|
||||
|
||||
本文档是 Ordo 对外行为的使用说明真源。**新增或变更对外 API、JSON 定义、扩展点、异常或运行时语义时,必须同步更新本文。** 未实现能力写在 [roadmap.md](roadmap.md),不要在这里当已支持功能描述。
|
||||
|
||||
版本:`0.0.1-SNAPSHOT`。语言:Java 17+。
|
||||
|
||||
## 1. 定位
|
||||
|
||||
Ordo 是嵌入宿主进程的审批引擎,入口是 `OrdoEngine`。
|
||||
|
||||
做:流程定义、实例推进、待办任务、条件路由、ACTION 副作用、审计事件、分页查询。
|
||||
|
||||
产品边界(不做,且暂不在开发计划):业务表单、用户体系、官方 REST、多租户。业务字段放在 `ProcessContext`(不可变 `Map<String, Object>`)。
|
||||
|
||||
开发计划(尚未提供,见 [roadmap.md](roadmap.md)):任务转派、到期升级、`CANCELLED`、定义不可变多版本、MySQL 方言。
|
||||
|
||||
## 2. 模块与接入
|
||||
|
||||
| 模块 | 何时用 |
|
||||
|---|---|
|
||||
| `ordo-api` | 始终:模型与 `OrdoEngine` |
|
||||
| `ordo-core` | 内存引擎 / 自己装配 `DefaultOrdoEngine` |
|
||||
| `ordo-storage-jdbc` | JDBC 持久化(PostgreSQL;测试可用 H2 PostgreSQL 模式) |
|
||||
| `ordo-spring-boot-starter` | Spring Boot 自动装配 |
|
||||
| `ordo-example` | `LeaveRequestExample` 内存演示 |
|
||||
|
||||
Starter **不携带** JDBC 驱动。生产加 `org.postgresql:postgresql`。Spring Boot 4 还需 `spring-boot-starter-flyway`,否则 Flyway 迁移不会执行。
|
||||
|
||||
先 `mvn install` 本仓库,宿主再依赖 `0.0.1-SNAPSHOT`。
|
||||
|
||||
### 2.1 内存引擎
|
||||
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>com.jetlumen</groupId>
|
||||
<artifactId>ordo-core</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
```java
|
||||
OrdoEngine ordo = new InMemoryOrdoEngine();
|
||||
// 可选:new InMemoryOrdoEngine(clock, assigneeResolver, routingCondition, actionHandler, listeners)
|
||||
```
|
||||
|
||||
进程退出数据即丢失。适合单测和本地试跑。
|
||||
|
||||
### 2.2 Spring Boot(JDBC)
|
||||
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>com.jetlumen</groupId>
|
||||
<artifactId>ordo-spring-boot-starter</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
需要已有 `DataSource`。`ordo.enabled` 缺省为 `true`。
|
||||
|
||||
```yaml
|
||||
ordo:
|
||||
enabled: true
|
||||
definitions:
|
||||
location: classpath*:ordo/*.json # 启动时对每个 JSON 调用 replace
|
||||
```
|
||||
|
||||
启动加载使用 `replace`:无 `RUNNING` 实例则整图替换;有运行中实例则保留库里的定义。
|
||||
|
||||
宿主用 `@Bean` 覆盖默认扩展点:
|
||||
|
||||
| Bean | 默认 |
|
||||
|---|---|
|
||||
| `AssigneeResolver` | 候选人字符串即办理人 |
|
||||
| `RoutingCondition` | 始终匹配(无条件边) |
|
||||
| `ActionHandler` | 空操作 |
|
||||
| `OrdoEventListener` | 可有多个,提交后按 Spring 顺序调用 |
|
||||
|
||||
未提供自定义 Bean 时,ACTION 步骤仍会推进流程,但 handler 什么都不做。
|
||||
|
||||
## 3. 流程定义
|
||||
|
||||
每个定义有 `id`、`name`、步骤列表、转移列表。步骤 id 在定义内唯一。每个步骤必须至少有一条出边(结束用 `to = null`)。同一 `from` 上 `priority` 不能重复。
|
||||
|
||||
### 3.1 代码构建
|
||||
|
||||
线性(每步无条件进下一步,最后一步结束):
|
||||
|
||||
```java
|
||||
ordo.register(ProcessDefinition.linear("leave-request", "Leave request", List.of(
|
||||
ApprovalStep.single("manager", "Manager approval", "maria"),
|
||||
ApprovalStep.single("hr", "HR approval", "henry")
|
||||
)));
|
||||
```
|
||||
|
||||
图(条件边 + ACTION):
|
||||
|
||||
```java
|
||||
new ProcessDefinition("leave-request-routed", "Leave request",
|
||||
List.of(
|
||||
ApprovalStep.action("notify-submitted", "Notify submitted", "leave-submitted-mail"),
|
||||
ApprovalStep.single("manager", "Manager approval", "maria"),
|
||||
new ApprovalStep("hr", "HR approval", List.of("henry"), ApprovalPolicy.ANY),
|
||||
ApprovalStep.action("notify-approved", "Notify approved", "leave-approved-mail")
|
||||
),
|
||||
List.of(
|
||||
StepTransition.always("notify-submitted", "manager"),
|
||||
StepTransition.when("manager", "hr", "days-gt-3", 0),
|
||||
StepTransition.when("manager", "notify-approved", null, 1),
|
||||
StepTransition.always("hr", "notify-approved"),
|
||||
StepTransition.end("notify-approved")
|
||||
));
|
||||
```
|
||||
|
||||
`register`:同 id 已存在则 `DefinitionAlreadyExistsException`。
|
||||
`replace`:整图覆盖;存在该定义的 `RUNNING` 实例则 `DefinitionInUseException`。
|
||||
|
||||
当前**没有**运行中实例锁定所用版本:`replace` 成功后新实例用新图,旧已结束实例仍按当时落库的任务理解历史。
|
||||
|
||||
### 3.2 JSON
|
||||
|
||||
`ProcessDefinitionParser.fromJson(String|InputStream)`。Spring 默认扫 `classpath*:ordo/*.json`。
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "leave-request-routed",
|
||||
"name": "Leave request",
|
||||
"startStep": "notify-submitted",
|
||||
"steps": [
|
||||
{
|
||||
"id": "notify-submitted",
|
||||
"name": "Notify submitted",
|
||||
"kind": "ACTION",
|
||||
"action": "leave-submitted-mail"
|
||||
},
|
||||
{
|
||||
"id": "manager",
|
||||
"name": "Manager approval",
|
||||
"candidates": ["maria"],
|
||||
"policy": "ANY"
|
||||
},
|
||||
{
|
||||
"id": "hr",
|
||||
"name": "HR approval",
|
||||
"candidates": ["henry"],
|
||||
"policy": "ANY"
|
||||
},
|
||||
{
|
||||
"id": "notify-approved",
|
||||
"name": "Notify approved",
|
||||
"kind": "ACTION",
|
||||
"action": "leave-approved-mail"
|
||||
}
|
||||
],
|
||||
"transitions": [
|
||||
{ "from": "notify-submitted", "to": "manager" },
|
||||
{ "from": "manager", "to": "hr", "when": "days-gt-3", "priority": 0 },
|
||||
{ "from": "manager", "to": "notify-approved", "priority": 1 },
|
||||
{ "from": "hr", "to": "notify-approved" },
|
||||
{ "from": "notify-approved", "to": null }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
字段:
|
||||
|
||||
| 字段 | 说明 |
|
||||
|---|---|
|
||||
| `startStep` | 可选。指定起始步骤 id;缺省为 `steps` 数组第一项。解析时会把该步旋到列表首位。 |
|
||||
| `kind` | `APPROVAL`(默认)或 `ACTION`。 |
|
||||
| `candidates` / `policy` | 仅审批步。`policy` 默认 `ANY`。审批步至少一名候选人,禁止重复。 |
|
||||
| `action` | 仅 ACTION 步,对应 `ActionHandler.execute` 的 key。审批步禁止带 `action`。 |
|
||||
| `from` / `to` / `when` / `priority` | `to` 为 `null` 或 JSON `null` 表示结束。`when` 空则无条件。`priority` 默认 0,**越小越先匹配**。 |
|
||||
|
||||
## 4. 实例与任务
|
||||
|
||||
### 4.1 生命周期
|
||||
|
||||
```
|
||||
start → RUNNING
|
||||
审批步:为每个候选人建 PENDING 任务
|
||||
ACTION 步:事务内记 PENDING 执行记录,提交后调 ActionHandler
|
||||
approve / 路由结束 → APPROVED
|
||||
reject(步被否决)→ REJECTED
|
||||
withdraw(仅发起人)→ WITHDRAWN,剩余 PENDING 任务 → SKIPPED
|
||||
```
|
||||
|
||||
```java
|
||||
ProcessInstance instance = ordo.start("leave-request", "alice",
|
||||
new ProcessContext(Map.of("requestId", "LEAVE-001", "days", 2)));
|
||||
|
||||
List<ApprovalTask> pending = ordo.findPendingTasksByInstanceId(instance.id());
|
||||
ordo.approve(pending.get(0).id(), "maria", "ok");
|
||||
|
||||
ordo.reject(taskId, "maria", "额度不足");
|
||||
ordo.withdraw(instance.id(), "alice", "计划有变");
|
||||
```
|
||||
|
||||
`start` 的 `initiator`、办理人 `actor` 均不可空白。
|
||||
|
||||
### 4.2 权限
|
||||
|
||||
- `approve` / `reject`:`actor` 必须等于该任务当前 `assignee`,否则 `UnauthorizedTaskOperationException`。
|
||||
- 任务非 `PENDING`:`TaskAlreadyCompletedException`。
|
||||
- `withdraw`:仅 `initiator`,否则 `UnauthorizedInstanceOperationException`;实例非 `RUNNING`:`InstanceAlreadyCompletedException`。
|
||||
|
||||
没有转派、没有管理员代批、没有系统取消。
|
||||
|
||||
### 4.3 状态
|
||||
|
||||
实例 `ProcessStatus`:`RUNNING`、`APPROVED`、`REJECTED`、`WITHDRAWN`。
|
||||
|
||||
任务 `TaskStatus`:`PENDING`、`APPROVED`、`REJECTED`、`SKIPPED`(同一步其它候选人已决定结果,或实例被撤回)。
|
||||
|
||||
`ApprovalTask.action`(`TaskAction`)仍表示**该任务**上的办理人/意见/时间;实例级时间线用 `ProcessEvent`,不要靠拼任务 action 还原流程史。
|
||||
|
||||
## 5. 会签 / 或签
|
||||
|
||||
一步多个 `candidates` 时由 `ApprovalPolicy` 决定:
|
||||
|
||||
| | ANY | ALL |
|
||||
|---|---|---|
|
||||
| 通过 | 任一人 `approve` 即过步,其余 PENDING 变 `SKIPPED` | 全部 `approve` 才过步 |
|
||||
| 驳回 | 所有候选人都 `reject` 才否决实例 | 任一人 `reject` 即否决实例,其余 PENDING 变 `SKIPPED` |
|
||||
|
||||
候选人创建任务前会经过 `AssigneeResolver.resolve(candidate, step, context)`,例如把角色名解析成用户 id。默认实现原样返回 candidate。
|
||||
|
||||
连续 ACTION 步会在同一次提交后依次执行,上限 32 跳,超出抛 `IllegalStateException`。
|
||||
|
||||
## 6. 条件路由
|
||||
|
||||
离开当前步时,取出全部 `from = 当前步` 的边,按 `priority` 升序。第一条满足下列条件的边生效:
|
||||
|
||||
- `conditionKey` 为空,或
|
||||
- `routingCondition.matches(conditionKey, instance.context()) == true`
|
||||
|
||||
没有匹配边:`NoRouteFoundException`,**整次 approve/start 事务回滚**(JDBC 下任务/实例都不会半更新)。
|
||||
|
||||
无条件边通常作为默认分支,`priority` 应大于带 `when` 的边。
|
||||
|
||||
`RoutingCondition` 只看到 `ProcessContext`,看不到任务意见。上下文在 `start` 时写入,运行中引擎**不会**改 context。
|
||||
|
||||
## 7. ACTION 步骤
|
||||
|
||||
进入 ACTION 步时:
|
||||
|
||||
1. 事务内插入 `ActionExecution`,状态 `PENDING`。
|
||||
2. 按转移进入下一步或结束实例(仍在同一事务)。
|
||||
3. 事务提交后调用 `ActionHandler.execute(actionKey, context)`。
|
||||
4. 成功 → `SUCCESS` + 事件 `ACTION_SUCCEEDED`;失败 → `FAILED`(`errorMessage`)+ `ACTION_FAILED` + 日志 WARNING。
|
||||
|
||||
**失败不回滚已提交的审批,不阻塞后续步骤,引擎不做重试。** 宿主用 `queryActionExecutions` 或 listener 自行补发。
|
||||
|
||||
```java
|
||||
@Component
|
||||
public class MailActions implements ActionHandler {
|
||||
@Override
|
||||
public void execute(String actionKey, ProcessContext context) {
|
||||
switch (actionKey) {
|
||||
case "leave-submitted-mail" -> { /* ... */ }
|
||||
case "leave-approved-mail" -> { /* ... */ }
|
||||
default -> throw new IllegalStateException("unknown action: " + actionKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 8. 审计与监听
|
||||
|
||||
`queryHistory(instanceId, page)`:该实例事件,**发生时间升序**。
|
||||
|
||||
`ProcessEventType`:
|
||||
|
||||
- `INSTANCE_STARTED` / `INSTANCE_APPROVED` / `INSTANCE_REJECTED` / `INSTANCE_WITHDRAWN`
|
||||
- `TASK_CREATED` / `TASK_APPROVED` / `TASK_REJECTED` / `TASK_SKIPPED`
|
||||
- `ACTION_SUCCEEDED` / `ACTION_FAILED`
|
||||
|
||||
字段:`id`、`instanceId`、可选 `taskId`/`stepId`/`actor`/`detail`、`occurredAt`。系统完成类事件 `actor` 可为空。
|
||||
|
||||
`OrdoEventListener.onEvent(ProcessEvent)` 在**事务提交之后**按事件顺序调用(含本轮 ACTION 结果)。单个 listener 抛错只打日志,不影响流程和其他 listener。
|
||||
|
||||
短假(提交邮件 → 经理批 → 通过邮件)一类时间线示例:
|
||||
|
||||
`INSTANCE_STARTED` → `TASK_CREATED` → `ACTION_SUCCEEDED` → `TASK_APPROVED` → `INSTANCE_APPROVED` → `ACTION_SUCCEEDED`
|
||||
|
||||
ACTION 成功事件发生在提交之后,因此排在同轮事务内写入的任务/实例事件后面。
|
||||
|
||||
## 9. 查询
|
||||
|
||||
`PageRequest.of(page, size)`:`page` 从 0 起,`size > 0`。`Page` 含 `content`、`totalElements`、`page`、`size`,以及 `totalPages()` / `hasNext()`。
|
||||
|
||||
| 方法 | 过滤 | 排序 |
|
||||
|---|---|---|
|
||||
| `queryTasks(TaskQuery, PageRequest)` | assignee、instanceId、definitionId、status、createdFrom/To | 创建时间降序 |
|
||||
| `queryInstances(InstanceQuery, PageRequest)` | definitionId、status、initiator、startedFrom/To | 开始时间降序 |
|
||||
| `queryDefinitions(PageRequest)` | 无过滤 | 定义 id 升序 |
|
||||
| `queryHistory(instanceId, PageRequest)` | 单实例 | 发生时间升序 |
|
||||
| `queryActionExecutions(instanceId, PageRequest)` | 单实例 | 开始时间升序 |
|
||||
|
||||
`TaskQuery.any().withAssignee("maria").withStatus(TaskStatus.PENDING)` 等 with 方法返回新对象。字段 `null` 表示不按该维过滤。
|
||||
|
||||
便捷方法(不分页):`findInstance`、`findTask`、`findTasks`、`findPendingTasksByAssignee`、`findPendingTasksByInstanceId`。
|
||||
|
||||
## 10. `OrdoEngine` 一览
|
||||
|
||||
| 方法 | 说明 |
|
||||
|---|---|
|
||||
| `register` / `replace` | 登记 / 整图替换定义 |
|
||||
| `start` | 发起;可选 `ProcessContext` |
|
||||
| `approve` / `reject` | 办理当前 PENDING 任务 |
|
||||
| `withdraw` | 发起人撤回 |
|
||||
| `find*` | 按 id / 待办索引读取 |
|
||||
| `queryTasks` / `queryInstances` / `queryDefinitions` | 分页列表 |
|
||||
| `queryHistory` / `queryActionExecutions` | 实例审计与 ACTION 记录 |
|
||||
|
||||
## 11. 异常
|
||||
|
||||
均继承 `OrdoException`(unchecked)。
|
||||
|
||||
| 类型 | 何时 |
|
||||
|---|---|
|
||||
| `DefinitionAlreadyExistsException` | `register` 撞 id |
|
||||
| `DefinitionNotFoundException` | `start` 等找不到定义 |
|
||||
| `DefinitionInUseException` | `replace` 时仍有 RUNNING 实例 |
|
||||
| `InstanceNotFoundException` | 撤回等找不到实例 |
|
||||
| `InstanceAlreadyCompletedException` | 对非 RUNNING 实例完成/撤回 |
|
||||
| `TaskNotFoundException` | 任务 id 不存在 |
|
||||
| `TaskAlreadyCompletedException` | 重复办理或已被 SKIPPED |
|
||||
| `UnauthorizedTaskOperationException` | actor ≠ assignee |
|
||||
| `UnauthorizedInstanceOperationException` | 非发起人撤回 |
|
||||
| `NoRouteFoundException` | 当前步没有匹配转移 |
|
||||
|
||||
参数空白等会抛 `IllegalArgumentException`,不属于 `OrdoException`。
|
||||
|
||||
## 12. 存储
|
||||
|
||||
Flyway 脚本在 `ordo-storage-jdbc` 的 `db/migration`(V1–V5)。表包括定义/步骤/候选人/转移、实例、任务、`ordo_process_event`、`ordo_action_execution`。
|
||||
|
||||
多 JVM 共享同一库时,多步写入走 `TransactionExecutor`,完成任务/实例用条件更新(仍 PENDING / 仍 RUNNING 才改),避免双花。
|
||||
|
||||
## 13. 未提供能力
|
||||
|
||||
开发计划中(见 [roadmap.md](roadmap.md)):转派、到期升级、`CANCELLED`、定义不可变多版本、MySQL 方言。
|
||||
|
||||
暂不在计划中:多租户、官方 REST Starter。REST 由宿主自建。
|
||||
Reference in New Issue
Block a user