2. 任务调度平台核心模型:实体关系与状态机
任务调度平台的核心在于对 Task(任务)、Job(作业)、Workflow(工作流)、Trigger(触发器) 和 Executor(执行器) 这五大实体的抽象与编排。理解它们之间的实体关系以及各自的状态机,是设计 OpenAPI 和事件驱动架构的基础。
2.1 五大核心实体定义
| 实体 | 英文 | 核心职责 | 生命周期特征 |
|---|---|---|---|
| 任务 | Task | 最小执行单元,定义具体的执行命令、脚本或 HTTP 请求 | 创建 → 就绪 → 运行 → 完成/失败 |
| 作业 | Job | 任务的逻辑容器,包含任务定义、重试策略、超时配置 | 启用 → 调度中 → 暂停 → 归档 |
| 工作流 | Workflow | 多个 Job 的有向无环图(DAG)编排,定义依赖与并行关系 | 草稿 → 发布 → 运行中 → 完成/终止 |
| 触发器 | Trigger | 驱动 Job 或 Workflow 执行的定时/事件源 | 绑定 → 激活 → 触发 → 失效 |
| 执行器 | Executor | 实际运行 Task 的物理或虚拟节点,负责资源隔离与日志采集 | 注册 → 在线 → 离线 → 注销 |
2.2 实体关系模型
五大实体通过以下关键关系构成调度平台的骨架:
- Job 与 Task:一对多关系。一个 Job 包含一个或多个 Task,Task 在 Job 的上下文中按顺序或并行执行。
- Workflow 与 Job:一对多关系。一个 Workflow 由多个 Job 组成,通过 DAG 边定义依赖(如 Job B 必须在 Job A 完成后启动)。
- Trigger 与 Job/Workflow:多对多关系。一个 Trigger 可以绑定多个 Job 或 Workflow;一个 Job 也可以被多个 Trigger 触发。
- Executor 与 Task:一对多关系。一个 Executor 在同一时刻可运行多个 Task,但每个 Task 只能分配给一个 Executor。
设计要点: 在 OpenAPI 设计中,Job 和 Workflow 是资源管理的核心端点(如
/api/v1/jobs、/api/v1/workflows),而 Task 实例通常作为子资源或事件流中的记录存在,不直接暴露为独立 CRUD 资源。
2.3 核心状态机
每个实体都拥有独立的状态机,状态转换是事件驱动的核心。下面以 Task 和 Job 为例说明。
2.3.1 Task 状态机
| 当前状态 | 触发事件 | 下一状态 | 说明 |
|---|---|---|---|
| PENDING | 调度器分配 Executor | RUNNING | Task 被分配给一个在线 Executor |
| RUNNING | 执行成功 | SUCCESS | Task 正常完成 |
| RUNNING | 执行失败 | FAILED | Task 异常退出 |
| RUNNING | 超时 | TIMEOUT | 超过 Job 配置的超时阈值 |
| FAILED | 重试策略触发 | PENDING | 重新进入调度队列 |
| PENDING | 手动取消 | CANCELLED | 用户通过 API 取消 |
2.3.2 Job 状态机
| 当前状态 | 触发事件 | 下一状态 | 说明 |
|---|---|---|---|
| ENABLED | Trigger 触发 | RUNNING | 开始执行 Job 内的 Task 序列 |
| RUNNING | 所有 Task 成功 | COMPLETED | Job 正常结束 |
| RUNNING | 任一 Task 失败且无重试 | FAILED | Job 整体失败 |
| ENABLED | 用户暂停 | PAUSED | 暂停后 Trigger 不再触发新实例 |
| PAUSED | 用户恢复 | ENABLED | 恢复调度 |
| COMPLETED / FAILED | 用户归档 | ARCHIVED | 历史数据清理 |
事件驱动设计提示: 每个状态转换都应发布对应的 Kafka 事件(如
task.state.changed、job.state.changed),下游消费者(如通知服务、监控面板)通过订阅这些事件实现解耦。
2.4 实体关系在 OpenAPI 中的体现
在 OpenAPI 规范中,实体关系通过资源嵌套和引用表达:
# 示例:Job 资源定义(OpenAPI 3.0 片段)
components:
schemas:
Job:
type: object
properties:
id:
type: string
format: uuid
name:
type: string
tasks:
type: array
items:
$ref: '#/components/schemas/TaskRef' # 引用 Task
trigger_id:
type: string
description: "绑定的 Trigger ID"
executor_group:
type: string
description: "执行器标签,用于调度匹配"
state:
$ref: '#/components/schemas/JobState'
TaskRef:
type: object
properties:
task_id:
type: string
order:
type: integer
description: "执行顺序"
避坑提示: 不要在 OpenAPI 中将 Workflow 的 DAG 结构直接嵌入 Job 定义。DAG 边应作为 Workflow 的独立子资源(如
/api/v1/workflows/{id}/edges),避免在更新 Job 时意外破坏依赖关系。
2.5 状态机与事件驱动的映射
每个状态转换对应一个 Kafka 事件主题(Topic),事件结构遵循统一格式:
| 事件主题 | Key | Value 关键字段 | 消费者示例 |
|---|---|---|---|
task.state.changed |
taskId | oldState, newState, executorId, timestamp | 日志服务、监控面板 |
job.state.changed |
jobId | oldState, newState, triggerId, timestamp | 通知服务、审计系统 |
workflow.state.changed |
workflowId | oldState, newState, currentJobId, timestamp | 可视化 DAG 面板 |
executor.heartbeat |
executorId | status, load, runningTaskIds, timestamp | 调度器、健康检查 |