Skip to content
bitzorcas
中EN

Guide

部署、版本与回滚

讲透定义快照、Checksum 幂等、Office/租户绑定、当前 Grayscale 语义、缓存失效、并发风险与发布 Runbook。

Last updated

Workflow 把“定义内容”和“新实例选择哪个定义”拆开。Deploy 创建版本快照;Publish/StartGrayScale/CompleteGrayScale/Rollback 修改 WorkflowDeployment 绑定。运行中的实例始终使用自己的 DefinitionId。

1. 数据模型

Definition Key

Definition v1 / checksum A

Definition v2 / checksum B

Tenant + Office binding

ActiveDefinitionId

PreviousDefinitionId

New instance

Existing instance

同 Key、Tenant、Checksum 的重复 Deploy 返回已有版本,不创建新行。版本号取当前最大值加一;没有数据库唯一约束或发布级分布式锁证据时,并发 Deploy 仍需测试竞争。

2. 部署定义

创建不可变版本
Result<WorkflowDefinition> deployed =
await repository.DeployAsync(
key: "matter-intake-approval",
name: "案件立案审批 v2",
jsonDefinition: json,
createBy: currentUserId,
tenantId: currentTenantId,
cancellationToken);
// 失败时不能读取 Value,先把稳定错误返回给调用方。
if (deployed.IsFailure)
return deployed.Error;
// 保存 DefinitionId,后续发布绑定必须使用它。
string definitionId = deployed.Value.DefinitionId!;

DeployAsync 当前只 Parse,不调用完整 Validate。推荐发布服务在 Deploy 前强制 ValidateDefinitionAsync;如果绕过,缺少结束节点或悬空边的可解析 JSON 可能入库。

3. 三层选择规则

新实例按以下顺序解析部署绑定:

  1. DefinitionKey + TenantId + 精确 OfficeId;
  2. DefinitionKey + TenantId + ALL;
  3. DefinitionKey + PLATFORM + ALL。

三层都没有命中时,发起即失败——没有”回退到该 Key 最新定义”的暗门,发布绑定因此是真正的门禁:一个定义若从未 Publish 过绑定,就不可能被任何新实例使用。运行记录始终携带租户上下文,精确到 Office 的差异版本由第一层优先匹配。

4. 正常发布

首次 Publish 创建 Active 绑定;再次 Publish 把旧 Active 移入 Previous,再把新 DefinitionId 设为 Active,状态为 Active。发布后失效对应部署缓存。

发布租户全局版本
// definitionId 必须来自已经校验并部署成功的不可变版本。
Result published = await repository.PublishDeploymentAsync(
definitionKey: "matter-intake-approval",
tenantId: currentTenantId,
officeId: null, // 规范化为 ALL
definitionId: definitionId,
ModifyBy: currentUserId,
cancellationToken);
// published 只代表绑定写入成功,不会迁移已经运行的实例。

Publish 会验证 DefinitionId 存在且 Key 匹配,但源码没有验证定义 TenantId 与绑定 TenantId 一致。跨租户定义发布必须由授权与 Store 约束补证。

5. “灰度”当前到底是什么

StartGrayScale 要求已有绑定,然后直接:

  • PreviousDefinitionId = 当前 Active;
  • ActiveDefinitionId = newDefinitionId;
  • Status = GrayScale。

所有后续新实例都会选新 Active。没有百分比、用户哈希、Office 子集、时间窗口或实验分桶。Status 只是运维标记,不参与版本选择。

StartGrayScale 也没有像 Publish 那样显式验证 newDefinitionId 存在且 Key 匹配。这是需要补齐的输入约束。

6. 完成与回滚

CompleteGrayScale 只把状态从 GrayScale 改为 Active。Rollback 把 Previous 放回 Active,并把 Previous 清空;已经用新版本发起的实例不变。

StartGrayScaleCompleteGrayScaleRollbackRollback if Previousretained

ActiveV1

GrayV2

ActiveV2

Rollback 只有一层 Previous,不是任意版本回滚栈。多次 Publish 会覆盖上一次 Previous;发布 Runbook 必须保存目标 DefinitionId 和实例影响范围。

7. 发布竞争

Deployment 保存没有 expectedVersion/CAS。两个管理员同时 Publish 时可能都读取同一 Active,然后后写覆盖前写,Previous 也可能不符合预期。需要数据库唯一键、部署行版本、事务和冲突响应。

定义版本分配同样是 read max + 1;并发创建需要唯一约束和重试。Checksum 幂等只能处理相同内容,不能解决不同内容同时抢同一 version。

8. 缓存一致性

RepositoryService 在保存绑定后调用 IWorkflowCache.InvalidateDeploymentAsync。FusionCache 有 Redis 时可通过 backplane 跨实例传播;无 Redis 时只有各实例 L1,其他节点可能继续读旧绑定直到过期。

上线前应验证:

  • 双 API 实例对 Publish/StartGrayScale/Rollback 的失效传播;
  • Redis/backplane 故障时最大陈旧时间;
  • 缓存失败是否改变发布返回值;
  • 回滚后所有节点选择同一 DefinitionId。

9. 建议发布 Runbook

  1. 冻结 Key,导出当前 Active/Previous/Status 与 Checksum。
  2. 对候选 JSON 运行 validate、simulation matrix 和真实集成测试。
  3. Deploy 并再次读取 DefinitionId、Version、Checksum。
  4. 在隔离租户或 Office 发布,发起验证实例。
  5. 检查任务、通知、Timer、Timeline、报表和缓存。
  6. 再切正式绑定;当前没有百分比灰度时必须缩小 Office/租户范围。
  7. 监控新旧 DefinitionId 的实例数、失败率和平均处理时间。
  8. 触发条件满足时 Rollback,并明确新版本在途实例的处置。

10. 版本兼容

新版本不能删除仍被旧实例引用的定义。Management.DeleteDefinitionAsync 当前只检查定义存在后直接删除,没有检查活跃实例、部署 Active/Previous 或缓存引用。删除定义是 P0/P1 管理风险,应在实现保护前从普通运维权限中收紧。

变量和节点 ID 也属于兼容契约:旧实例按旧图继续运行;迁移工具若把实例切到新节点,必须提供映射、默认值和回滚。

11. 验证命令

Terminal window
# 部署与版本实现。
rg -n "DeployAsync|PublishDeploymentAsync|StartGrayScaleAsync|RollbackDeploymentAsync" src/Framework/BitzOrcas.Workflow -g '*.cs'
# 查找 DefinitionId 的活跃引用与删除保护。
rg -n "DeleteDefinitionAsync|ActiveDefinitionId|PreviousDefinitionId|DefinitionId" src/Framework/BitzOrcas.Workflow src/Platform/Workflow -g '*.cs'

下一篇:运行实例

100%

滚轮或按钮缩放 · 放大后拖动画面 · 双击切换 100% / 200%