Skip to content
bitzorcas
中EN

Guide

Operations 后台作业运行控制

解释代码目录、持久化定义、调度修改、启停、立即执行、分派器、审计与多实例收敛的真实边界。

Last updated

后台作业控制面横跨三份事实:代码生成的 IBackgroundJobCatalog、SysBackgroundJobDefinition 持久化定义,以及 JobHost/Api fallback 的实际调度状态。Operations 已能修改持久化定义并立即执行,但查询和调度收敛仍不能简单视为一个强一致系统。

1. 三份事实

代码 Catalog

Seed / metadata sync

SysBackgroundJobDefinition

JobHost / API fallback

GET /api/operations/jobs

PUT / start / stop

execute

JobExecutorDispatcher

代码目录拥有 JobName、Source、Description、ModuleName、IsCritical 等声明;持久化定义拥有运行时 Cron/Interval/Enabled;调度宿主消费持久化状态。

2. 查询的当前事实源

OperationsService.GetJobScheduleAsync 直接遍历 _jobCatalog.Declarations,按 JobName 排序并投影。它不读取 IBackgroundJobDefinitionStore。

因此 PUT/stop 成功后,GET /api/operations/jobs 仍可能展示代码目录默认值。现有测试名和注释声称返回持久化值,但 Handler 只是代理 IOperationsService,没有证明真实服务读取 Store。

这是文档必须明确的源码/测试意图漂移。

3. 调度表示

DTO 的字段名仍是 CronExpression:

  • Cron 作业返回原表达式;
  • Interval 作业返回 interval:{seconds}s;
  • 无调度返回 null。

客户端必须按 interval: 前缀区分,而不能把所有非空字符串交给 Cron parser。

4. 持久化聚合不变量

BackgroundJobDefinition 直接承载编译期 ORM metadata,表名 SysBackgroundJobDefinition,JobName 唯一且支持软删。

运行时调度规则:

  • Cron 与 Interval 不能同时设置;
  • Interval 必须为正数;
  • Enabled=true 时至少有一种调度;
  • Disabled 时可无调度;
  • Cron 当前只做 trim 和 160 长度限制,不验证语法。

5. 更新调度

切换到间隔调度
var command = new UpdateBackgroundJobDefinition.Command(
JobName: "export-execution",
CronExpression: null,
IntervalSeconds: 45,
Enabled: true);
// ① Store 先按稳定 JobName 读取非软删定义。
// ② 聚合一次性验证并替换三项运行时字段。
// ③ SaveAsync 加入当前工作单元,返回 interval:45s 投影。
Result<JobScheduleEntry> result =
await mediator.Send(command, cancellationToken);

Update 不允许创建任意 JobName。定义必须先由代码目录和 seed 进入数据库。

6. 启停不会清空调度

SetBackgroundJobEnabled 读取当前定义,保留 Cron/Interval,只修改 Enabled。

start 可能失败:一个 disabled 且没有任何调度的定义不能被直接启用,需先 PUT 一个有效调度。

7. HTTP 示例

停止作业
POST /api/operations/jobs/workflow-timer/stop
Authorization: Bearer <token-with-operations.jobs.manage>
更新调度
PUT /api/operations/jobs/export-execution
Content-Type: application/json
Authorization: Bearer <token-with-operations.jobs.manage>
{
"cronExpression": null,
"intervalSeconds": 60,
"enabled": true
}

手写端点组为这些写路由统一启用认证、userPolicy 限流和精确管理权限。

8. 立即执行路径

ExecuteBackgroundJob.Command 实现 INonTransactionalCommand,避免把长时间外部作业包进通用数据库事务。

Handler 先确认定义存在,再把稳定 JobName 交给 IJobExecutorDispatcher,并用 IBackgroundJobExecutionAuditor 包裹执行。

9. 分派器的启动期闭包

JobExecutorDispatcher 构造时验证:

  • 同一 JobName 没有重复 binding;
  • Catalog 每个声明都有 binding;
  • 没有 Catalog 之外的多余 binding。

不满足时抛 InvalidOperationException,使错误尽早暴露。执行期只访问已经验证的字典,不动态扫描 DI。

10. 执行审计语义

审计信封记录开始/结束、成功/失败、错误码与 correlation。业务 Result 失败原样返回;异常和取消先尝试写失败审计,再重新抛出。

审计 sink 失败只记录 warning,不改变作业结果。这是可用性优先的 best-effort 选择,合规环境需要额外的审计健康门禁。

11. 修改调度的审计缺口

Update/start/stop 没有显式活动审计;它们依赖通用命令审计是否捕获足够 before/after 信息。当前说明书不能承诺每次调度变化都保存旧值、新值、操作者和原因。

管理命令也没有审批、变更原因、版本或并发令牌。两个管理员最后写入者获胜。

12. 多实例传播

Store 更新成功只表示定义持久化。是否以及何时影响 Quartz 或 API fallback,取决于各宿主的 reload/poll 机制。

Operations 响应没有返回调度器实例确认、配置版本或生效时间。商业控制面需要“desired state → observed state”模型,而不只是一次数据库写入。

13. 手动执行与 Enabled

Handler 只确认定义存在,不检查 Enabled。因此停止自动调度不一定禁止管理员手动 execute。

这是合理但必须显式的产品语义:Enabled 表示自动调度开关,不是作业能力总开关。若需要熔断,应增加独立 suspension/kill-switch 状态。

14. 故障诊断

NotFound:检查代码 Catalog、seed step、软删状态和目标环境数据库。

ScheduleConflict:请求同时提供 Cron 与 Interval。

ScheduleRequired:尝试启用无调度定义。

立即执行失败:先看 BackgroundJob 审计记录,再定位 binding 的业务错误;审计缺失还要检查 sink 健康。

GET 与 PUT 响应不一致:当前 GET 投影 Catalog,这是已知边界,不应反复刷新掩盖。

15. 测试重点

已有测试覆盖调度类型切换、无效更新不写 Store、启停保留调度、Manage 授权、立即执行成功/业务失败/异常/取消审计、API 无权限 403 与管理路由。

仍需补:真实 Service 的 GET-after-PUT、Cron 语法、并发更新、调度器收敛、多实例 reload、审计 sink 故障告警、disabled 手动执行策略、作业超时与取消。

16. GA 补全顺序

  1. GET 读取持久化 desired state,并同时展示 Catalog default;
  2. 增加 observed scheduler state 与实例心跳;
  3. 定义版本/ETag,拒绝丢失更新;
  4. 结构化 Cron 验证与下一次执行时间预览;
  5. 调度变更 before/after 审计、原因与可选审批;
  6. 发布 reload 事件并等待实例确认;
  7. 手动执行幂等键、超时、取消与并发策略;
  8. 建立 JobHost 和 API fallback 的同一合同套件。

17. 测试命令

Terminal window
# Application 行为。
dotnet test tests/BitzOrcas.Application.Tests \
--filter FullyQualifiedName~BackgroundJobManagementTests
# HTTP 管理表面。
dotnet test tests/BitzOrcas.Integration.Tests \
--filter FullyQualifiedName~BackgroundJobManagementApiTests
# Catalog/binding/Host 完整性。
dotnet test tests/BitzOrcas.Architecture.Tests \
--filter 'FullyQualifiedName~BackgroundJobIntakeTests|FullyQualifiedName~OperationsRuntimeSurfaceTests'

Operations 总览 · 安全与 GA

100%

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