3. 接口契约总览:契约分层架构与版本化策略
GoDAG 调度系统的边界接口契约并非扁平化的单一协议,而是按照职责边界划分为三个清晰的层次:用户层、调度层和执行层。每一层面向不同的调用方,承载不同的语义和约束。同时,契约本身需要具备可演进的版本化能力,以兼容系统升级与接口变更。
3.1 契约分层架构
三层契约的划分依据是调用方与系统模块之间的物理边界和逻辑职责。用户层面向外部业务系统,调度层面向内部编排引擎,执行层面向具体的任务执行器。三者形成自上而下的依赖关系,下层为上层提供能力抽象。
核心原则:每一层契约只对本层的调用方负责,禁止跨层直接调用。用户层契约不感知执行器细节,执行层契约不暴露调度策略。
3.2 各层契约核心要素
每一层契约由一组核心接口和数据结构构成。下表列出各层的关键契约要素及其语义说明:
| 契约层 | 核心接口 | 输入 / 输出 | 关键约束 |
|---|---|---|---|
| 用户层 | SubmitDAG、GetDAGStatus、CancelDAG |
DAG 定义 JSON / 状态枚举 + 结果数据 | 幂等提交、最大 DAG 深度 ≤ 100 |
| 调度层 | ResolveDependencies、ScheduleTasks |
任务拓扑图 / 调度计划 | 无环保证、资源配额校验 |
| 执行层 | RunTask、ReportStatus、StreamLogs |
任务上下文 / 状态变更事件 | 超时控制、重试次数 ≤ 3 |
设计要点:用户层契约应保持稳定,避免频繁变更;调度层和执行层契约可以随内部优化迭代,但必须保证向后兼容。
3.3 契约版本化策略
接口契约的版本化是保障系统演进过程中上下游兼容性的核心手段。GoDAG 采用 语义化版本 + 兼容性矩阵 的双重策略。
3.3.1 版本号规范
每个契约接口的版本号遵循 MAJOR.MINOR.PATCH 格式:
- MAJOR:不兼容的接口变更(如删除字段、修改必填项)。
- MINOR:向后兼容的功能新增(如增加可选字段、新增接口)。
- PATCH:内部修复或文档更新,不涉及接口语义变化。
3.3.2 兼容性矩阵
不同层之间的版本依赖关系通过兼容性矩阵定义,确保调度层和执行层可以独立升级:
| 调用方版本 | 被调用方版本 | 兼容性 | 说明 |
|---|---|---|---|
| 用户层 v1.0 | 调度层 v1.x | ✅ 完全兼容 | MAJOR 相同,MINOR 可高可低 |
| 用户层 v1.0 | 调度层 v2.0 | ❌ 不兼容 | 需升级用户层或启用适配层 |
| 调度层 v2.1 | 执行层 v2.x | ✅ 兼容 | MINOR 版本内可互操作 |
| 调度层 v2.0 | 执行层 v1.5 | ⚠️ 有条件兼容 | 需检查具体接口变更日志 |
3.3.3 版本协商与降级
在运行时,调用方与被调用方通过握手协议协商版本:
// 版本协商请求示例
{
"caller": "user-service",
"caller_version": "1.2.0",
"supported_apis": ["SubmitDAG", "GetDAGStatus"],
"min_compatible_version": "1.0.0"
}
// 版本协商响应示例
{
"status": "ok",
"selected_version": "1.2.0",
"deprecated_fields": ["callback_url"],
"upgrade_hint": "v2.0 will remove callback_url, use event_subscription instead"
}
注意:当 MAJOR 版本不匹配时,系统应拒绝调用并返回明确的错误码,避免数据损坏或逻辑错误。建议在网关层统一做版本路由。
3.4 契约分层与版本化的协同关系
分层架构与版本化策略共同构成了 GoDAG 的接口治理基础。下图展示了两者如何协同工作:
3.5 契约定义示例(用户层)
以下是一个用户层契约的 Protobuf 定义片段,展示了版本化字段和兼容性设计:
syntax = "proto3";
package godag.user.v1;
import "google/protobuf/timestamp.proto";
// DAG 提交请求
message SubmitDAGRequest {
string dag_id = 1; // 必填,全局唯一
string name = 2; // 必填
repeated TaskNode tasks = 3; // 必填,任务节点列表
map<string, string> labels = 4; // 可选,标签元数据
// v1.1 新增:任务超时全局配置
optional int32 global_timeout_seconds = 5;
// v1.2 新增:事件订阅配置
repeated EventSubscription subscriptions = 6;
}
message TaskNode {
string task_id = 1;
string type = 2; // 任务类型
repeated string depends_on = 3; // 依赖任务 ID 列表
bytes payload = 4; // 任务参数
}
message EventSubscription {
string event_type = 1; // 事件类型
string callback_url = 2; // 回调地址
}
message SubmitDAGResponse {
string dag_id = 1;
string status = 2; // "pending" | "running" | "completed"
google.protobuf.Timestamp created_at = 3;
}
版本化设计要点:
- 新增字段使用
optional修饰,保证旧客户端不传值时仍可正常工作。 - 枚举值使用开放枚举(允许未知值),避免新增枚举导致反序列化失败。
- 每个接口文件在 package 路径中标注 MAJOR 版本(如
v1、v2)。