# 同步编排流程规范 (Pipeline Specification) 本文档定义了完整的同步编排流程,包括各阶段的职责、节点状态转换和检查点。 > **详细的状态定义和转换规则,请参考**: [STATE_DEFINITIONS.md](../sync_system/STATE_DEFINITIONS.md) --- ## 流程概览 同步系统的完整执行流程分为 5 个阶段: ``` ┌─────────────────────────────────────────────────────────────┐ │ Stage 0: 初始化 (Initialization) │ ├─────────────────────────────────────────────────────────────┤ │ - 创建 Collection (Local/Remote) │ │ - 创建 BindingManager │ │ - 注册 SyncStrategy (各业务类型) │ │ - 创建 DataSource (Local/Remote) │ └─────────────────────────────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────────────────────┐ │ Stage 1: 数据加载 (Data Loading) │ ├─────────────────────────────────────────────────────────────┤ │ 节点状态: binding_status=UNCHECKED, action=NONE, status=PENDING │ │ - Persistence.load_nodes() → 从持久化恢复 │ │ - DataSource.load_all() → 从数据源加载 │ │ - BindingManager.load_bindings() → 加载绑定关系 │ └─────────────────────────────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────────────────────┐ │ Stage 2 & 3: 策略执行与同步 (按 node_type 顺序) │ ├─────────────────────────────────────────────────────────────┤ │ For each node_type in sync_order: │ │ ┌─────────────────────────────────────────────────┐ │ │ │ 2.1 bind() → 绑定判定 │ │ │ │ 2.2 create() → 设置 CREATE action │ │ │ │ └─ 内联 ID 解析 + 前置检查 │ │ │ │ 2.3 Commit Creates → 立即同步 CREATE 节点 │ │ │ │ └─ DataSource.sync_all(poll_async=True) │ │ │ │ 2.4 update() → 设置 UPDATE action │ │ │ │ └─ 内联 ID 解析 + 前置检查 │ │ │ │ 2.5 Commit Updates → 立即同步 UPDATE 节点 │ │ │ │ └─ DataSource.sync_all(poll_async=True) │ │ │ └─────────────────────────────────────────────────┘ │ │ │ │ 说明: │ │ - 每个 node_type 完整同步后才处理下一个(保证依赖顺序) │ │ - commit 操作内部包含异步轮询,无需独立轮询阶段 │ │ - sync_all() 自动过滤 action=CREATE/UPDATE 的节点 │ └─────────────────────────────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────────────────────┐ │ Stage 4: 同步结果报告 (Summary Report) │ ├─────────────────────────────────────────────────────────────┤ │ - 打印同步结果摘要 │ │ * 节点统计(按 action/status 分类) │ │ * 绑定关系统计 │ │ * 异常节点检查(data_id 缺失、绑定缺失等) │ │ - 收集统计信息(成功/失败/残留问题) │ └─────────────────────────────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────────────────────┐ │ Stage 5: 状态持久化 (State Persistence) │ ├─────────────────────────────────────────────────────────────┤ │ - Collection.persist() → 保存节点状态 │ │ - BindingManager.persist() → 保存绑定关系 │ └─────────────────────────────────────────────────────────────┘ ↓ 【流程完成】 ``` --- ## 各阶段节点状态 ### Stage 0: 初始化 **输出**: 所有组件实例化完成。 --- ### Stage 1: 数据加载 **节点状态**: ```python binding_status = BindingStatus.UNCHECKED # 未判定 action = SyncAction.NONE # 无动作 status = SyncStatus.PENDING # 待处理 data_id = <从数据源加载> # 已有业务ID origin_data = <从数据源加载> # 原始数据快照 data = <从数据源加载> # 当前数据 depend_ids = <从数据源加载> # 依赖节点列表 ``` **关键点**: - `data_id` 在加载时**必定有值**(来自数据源) - 只有待创建的新节点 `data_id` 才可能为 ""(空字符串) - 从持久化恢复时应重置所有 `action` 为 `NONE` - `binding_status` 初始值是 `UNCHECKED`,不是 `None` --- ### Stage 2.1: Bind (状态判定) **状态转换**: `binding_status: UNCHECKED → NORMAL/MISSING/ABNORMAL/WARNING/DEPENDENCY_ERROR` **可能的结果状态**: | 结果状态 | 含义 | 占比 | |---------|------|-----| | **NORMAL** | 有绑定,数据健康 | 大部分 | | **MISSING** | 无绑定,孤儿节点 | 少量 | | **ABNORMAL** | 有绑定,自身数据损坏 | 极少 | | **WARNING** | 有绑定,对方数据损坏 | 极少 | | **DEPENDENCY_ERROR** | 依赖未满足 | 少量 | **详细规则**: 参考 [STATE_DEFINITIONS.md § 1-3](../sync_system/STATE_DEFINITIONS.md) **补充约束**: - 若依赖节点 `binding_status = NORMAL` 但 `data_id` 为空(含 `status = FAILED`),视为依赖阻断。 - 只要依赖节点已回填 `data_id`,即使其 `status = FAILED`,后续类型仍允许进入 Create/Update。 - 自动绑定只在**业务键完整且唯一**时才尝试: - 若业务键字段缺失(如 `serial_number = null`),设置 `binding_status = WARNING`,并在 `node.error` 记录原因:`Auto-bind skipped: missing fields ...`。 - 若同一业务键出现多对多/多对一,设置 `binding_status = WARNING`,并在 `node.error` 记录原因:`Auto-bind skipped: ambiguous candidates`。 - 以上情况仅记录 **Warning**,不进行自动绑定。 --- ### Stage 2.2: Create (孤儿处理) **状态转换**: `action: NONE → CREATE` (对 MISSING 节点) **补充约束**: - `binding_status = WARNING` 的节点不会进入 CREATE(`create()` 只查找 MISSING 节点) - 创建时会通过 `IDResolver.resolve_and_validate()` 二次验证依赖 ID,失败则设置 `DEPENDENCY_ERROR` **副作用**: - 在对方 Collection 创建新节点 - 新节点的 `binding_status = NORMAL, action = CREATE, data_id = ""` - 建立绑定记录 - 原 MISSING 节点也变为 `NORMAL` **示例**: ``` Before: local_node: binding_status=MISSING, action=NONE After Create: local_node: binding_status=NORMAL, action=NONE remote_node (新建): binding_status=NORMAL, action=CREATE, data_id="" 绑定记录: local_id ↔ remote_temp_id ``` --- ### Stage 2.3: Update (差异同步) **状态转换**: `action: NONE → UPDATE` (对 NORMAL 且有差异的节点) **前提条件**: - `binding_status = NORMAL` - `status != FAILED`(保护上次失败的状态和错误信息) - `compute_diff()` 判定有差异 - 配置的 `update_direction` 决定哪一方节点设置 UPDATE **内联检查**: - 目标节点 `data_id` 为空 → `status = PRECONDITION_FAILED` - `IDResolver.resolve_and_validate()` 失败 → `status = PRECONDITION_FAILED` - Handler 校验后无实际变更字段 → `action` 降级为 `NONE`(不提交) --- ### Stage 2 & 3: 策略执行与同步 **执行顺序**: 按 `sync_order` 顺序逐个处理 node_type **单个 node_type 的完整流程**: ``` For node_type in sync_order: ┌─────────────────────────────────────────────┐ │ 2.1 Bind - 绑定判定 │ │ - 设置 binding_status: NORMAL/MISSING/... │ └─────────────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────┐ │ 2.2 Create - 创建策略 │ │ - 处理 MISSING 节点,设置 action=CREATE │ │ - 内联 ID 解析验证 (resolve_and_validate) │ └─────────────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────┐ │ 2.3 Commit Creates - 立即同步 CREATE │ │ - DataSource.sync_all(poll_async=True) │ │ - 自动过滤 action=CREATE 的节点 │ │ - 内部包含异步轮询(IN_PROGRESS→SUCCESS)│ │ - ⭐ 执行 data_id 回填和绑定更新 │ └─────────────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────┐ │ 2.4 Update - 更新策略 │ │ - 处理差异节点,设置 action=UPDATE │ │ - 内联 ID 解析验证 + data_id 检查 │ │ - FAILED 节点自动跳过 │ └─────────────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────┐ │ 2.5 Commit Updates - 立即同步 UPDATE │ │ - DataSource.sync_all(poll_async=True) │ │ - 自动过滤 action=UPDATE 的节点 │ │ - 内部包含异步轮询(IN_PROGRESS→SUCCESS)│ └─────────────────────────────────────────────┘ ↓ 下一个 node_type ``` **关键特性**: 1. **按类型顺序**: 每个 node_type 完全同步后才处理下一个(保证依赖顺序) 2. **立即提交**: create/update 后立即同步,不等待所有策略执行完 3. **内置轮询**: `sync_all(poll_async=True)` 内部自动轮询异步任务 4. **data_id 回填**: CREATE 成功后立即回填 data_id,下游依赖可用 **同步状态转换**: **同步接口(一步式)**: ``` action=CREATE, API 成功 → status=SUCCESS, data_id=<远程ID> action=CREATE, API 失败 → status=FAILED, error=<错误信息> action=UPDATE, API 成功 → status=SUCCESS action=UPDATE, API 失败 → status=FAILED, error=<错误信息> action=NONE → status=PENDING (不执行) ``` **异步接口(两步式,内置轮询)**: ``` action=CREATE, 提交成功 → status=IN_PROGRESS, task_id=<任务ID> status=IN_PROGRESS, 轮询中... → status=IN_PROGRESS (保持) status=IN_PROGRESS, 轮询成功 → status=SUCCESS, data_id=<远程ID> status=IN_PROGRESS, 轮询失败 → status=FAILED, error=<错误信息> status=IN_PROGRESS, 超时 → status=FAILED, error="Timeout" ``` **关键副作用**(由 DataSource 在 sync_all 中执行): - CREATE 成功: `data_id` 从 "" 更新为远程分配的 ID,并回写 `data` 主键字段 - CREATE 成功: 绑定记录从临时ID更新为真实ID - UPDATE 成功: `origin_data` 更新为当前 `data` - DELETE 成功: 移除绑定记录 **skip_sync 处理**: - 如果 `strategy.skip_sync = True`,跳过 create/update/commit 步骤 - bind 步骤始终执行(用于状态判定) **详细规则**: 参考 [STATE_DEFINITIONS.md § 5](../sync_system/STATE_DEFINITIONS.md) --- ### Stage 4: 同步结果报告 **目标**: 打印同步结果摘要,帮助用户了解同步情况 **报告内容**: 1. **节点统计**:按 node_type 统计各种 action/status 的节点数量 2. **绑定关系**:每个 node_type 的绑定记录数 3. **异常检查**:扫描并报告异常情况: - CREATE 成功但 data_id 为空(DataSource 回填失败) - CREATE 成功但绑定记录缺失 - UPDATE/CREATE 失败的节点及错误原因 **输出示例**: ``` ================================================================================ 📊 Local Collection Summary ================================================================================ Node Type Bindings Create Update Delete None Total -------------------------------------------------------------------------------- project 5/5 0(0/0/0) 2(2/0/0) 0(0/0/0) 3 5(5/0/0) contract 10/12 2(2/0/0) 5(5/0/0) 0(0/0/0) 5 12(12/0/0) ``` **注意**: 此阶段不修改任何状态,仅作为信息展示。 --- ### Stage 5: 状态持久化 **持久化内容**: - `binding_status`, `action`, `status` 的最终值 - `data_id` (可能在 CREATE 后更新) - `error` (如果失败) - 绑定关系的完整映射 --- ## 错误处理策略 | 阶段 | 失败类型 | 处理策略 | |------|---------|---------| | Stage 0 | 初始化失败 | **终止流程**,抛出异常 | | Stage 1 | 数据加载失败 | **终止流程**,抛出异常 | | Stage 2 & 3 | 代码异常 | **终止流程**,抛出异常 | | Stage 2: create/update 内联检查 | 依赖ID未解析、data_id缺失 | **继续流程**,节点标记为 DEPENDENCY_ERROR 或 PRECONDITION_FAILED | | Stage 2 & 3 | API 调用失败 | **继续流程**,标记节点 FAILED | | Stage 4 | - | 总是继续,仅作为报告 | | Stage 5 | 持久化失败 | **记录错误**,不影响内存状态 | --- ## 节点状态完整时间线 ``` ┌──────────────┬─────────────┬────────┬────────┬─────────┐ │ 阶段 │ binding_ │ action │ status │ data_id │ │ │ status │ │ │ │ ├──────────────┼─────────────┼────────┼────────┼─────────┤ │ 数据加载 │ UNCHECKED │ NONE │PENDING │ 已加载 │ │ Bind │ NORMAL/... │ NONE │PENDING │ 已加载 │ │ Create │ NORMAL │ CREATE │PENDING │ ""* │ │ Commit Create│ NORMAL │ CREATE │SUCCESS │ 远程ID** │ │ Update │ NORMAL │ UPDATE │PENDING │ 已加载 │ │ Commit Update│ NORMAL │ UPDATE │SUCCESS │ 已加载 │ └──────────────┴─────────────┴────────┴────────┴─────────┘ * 新创建的节点 data_id 初始为 "" ** CREATE 成功后 data_id 立即更新为远程分配的ID,下游依赖可用 ``` --- ## 配置驱动的流程控制 ### 跳过某些阶段 ```python pipeline_config = { "skip_bind": False, # 是否跳过 bind "skip_create": False, # 是否跳过 create "skip_update": False, # 是否跳过 update "skip_post_check": False, # 是否跳过同步后检查 "fail_on_warning": False, # Pre-Check 时是否将 WARNING 视为失败 } ``` > **注意**:`skip_pre_check` 已移除,原 `_pre_commit_check` 逻辑已内联到 create/update 方法中。 ``` ### 策略预设应用 ```python # 首次同步:启用自动绑定,双向创建 for strategy in strategies: strategy.apply_preset("first_sync") # 日常同步:仅推送更新 for strategy in strategies: strategy.apply_preset("push_only") ``` --- ## 幂等性保证 **要求**: 同一个 Collection 的多次同步应该是幂等的。 **设计保证**: 1. **Bind 阶段**: 基于绑定记录判定,已绑定节点不会重复绑定 2. **Create 阶段**: 已有绑定的节点 (NORMAL) 不会重复创建 3. **Update 阶段**: 基于 `compute_diff()` 判定,无差异则不执行 4. **Sync 阶段**: `action=NONE` 的节点跳过执行 **前提条件**: - 绑定记录正确持久化 - 节点的 `binding_status` 正确保存和加载 - `compute_diff()` 逻辑准确 --- ## 监控和日志 ### 关键指标 | 指标 | 含义 | 阶段 | |------|------|-----| | `nodes_loaded` | 加载的节点总数 | Stage 1 | | `nodes_normal` | NORMAL 状态节点数 | Stage 2.1 | | `nodes_missing` | MISSING 状态节点数 | Stage 2.1 | | `nodes_abnormal` | ABNORMAL+WARNING 节点数 | Stage 2.1 | | `nodes_dep_error` | DEPENDENCY_ERROR 节点数 | Stage 2.1 | | `actions_create` | CREATE 动作节点数 | Stage 2.2 | | `actions_update` | UPDATE 动作节点数 | Stage 2.3 | | `sync_success` | 同步成功节点数 | Stage 3 | | `sync_failed` | 同步失败节点数 | Stage 3 | | `success_rate` | 成功率 (success/total) | Stage 4 | ### 日志级别 ``` INFO: 流程阶段切换、统计信息 DEBUG: 节点级别的详细操作 WARN: 检查发现的警告、同步失败 ERROR: 检查发现的错误、致命异常 ``` --- ## 参考文档 - [STATE_DEFINITIONS.md](../sync_system/STATE_DEFINITIONS.md) - 详细的状态定义和转换规则 - [CHECK_SPEC.md](./CHECK_SPEC.md) - 检查点的实现细节和代码示例(可选) # 1. 持久化 Collection await local_collection.persist() await remote_collection.persist() # 2. 持久化 Binding await binding_manager.persist() ``` **持久化内容**: - 节点的 `binding_status`, `action`, `status`, `error` - 节点的 `data_id`(可能在 CREATE 后更新) - 绑定关系的完整映射 --- ## 错误处理策略 ### 各阶段的失败处理 | 阶段 | 失败原因示例 | 处理策略 | |------|------------|---------| | Stage 1: 数据加载 | 网络错误、文件缺失 | **终止流程**,抛出异常 | | Stage 2.1: Bind | 代码bug | **终止流程**,抛出异常 | | Stage 2.2-2.3: Create/Update | 代码bug | **终止流程**,抛出异常 | | Stage 2: create/update 内联检查 | 依赖ID未解析、data_id缺失 | **继续流程**,节点标记为 DEPENDENCY_ERROR 或 PRECONDITION_FAILED | | Stage 3: Physical Sync | API错误、权限不足 | **继续流程**,标记节点为 FAILED | | Stage 4: Post-Sync Check | 部分节点同步失败 | **继续流程**,打印警告 | | Stage 5: Persistence | 磁盘满、权限错误 | **记录错误**,但不影响内存状态 | ### 部分成功的处理 在 Stage 3 中,允许部分节点成功、部分失败: - 成功的节点: `status = SUCCESS` - 失败的节点: `status = FAILED`, `error = "错误信息"` Post-Sync Check 会统计成功率并给出警告。 --- ## 配置驱动的流程控制 ### 跳过某些阶段 通过配置控制哪些阶段执行: ```python pipeline_config = { "skip_bind": False, # 是否跳过 bind "skip_create": False, # 是否跳过 create "skip_update": False, # 是否跳过 update "skip_post_check": False, # 是否跳过同步后检查 "fail_on_warning": False, # 是否将 WARNING 也视为失败 } ``` ### 策略预设应用 在 Stage 2 之前,可以应用策略预设: ```python # 首次同步:启用自动绑定,双向创建 for strategy in strategies: strategy.apply_preset("first_sync") # 日常同步:仅推送更新 for strategy in strategies: strategy.apply_preset("push_only") ``` --- ## 监控和日志 ### 关键指标 在各阶段收集以下指标: | 指标 | 含义 | |------|------| | `nodes_loaded` | 加载的节点总数 | | `nodes_bound` | 成功绑定的节点数 | | `nodes_missing` | MISSING 状态的节点数 | | `nodes_abnormal` | ABNORMAL/WARNING 状态的节点数 | | `nodes_created` | CREATE 动作的节点数 | | `nodes_updated` | UPDATE 动作的节点数 | | `sync_success` | 同步成功的节点数 | | `sync_failed` | 同步失败的节点数 | | `errors_count` | 检查发现的 ERROR 数量 | | `warnings_count` | 检查发现的 WARNING 数量 | ### 日志级别 ``` INFO: 流程阶段切换、统计信息 DEBUG: 节点级别的详细操作 WARN: 检查发现的警告 ERROR: 检查发现的错误、异常 ``` --- ## 幂等性保证 **要求**: 同一个 Collection 的多次同步应该是幂等的。 **设计保证**: 1. **Bind 阶段**: 基于绑定记录判定状态,已绑定的节点不会重复绑定 2. **Create 阶段**: 已有绑定的节点(NORMAL)不会重复创建 3. **Update 阶段**: 基于 `compute_diff()` 判定,无差异则不执行 4. **Sync 阶段**: DataSource 根据 `action` 执行,`action=NONE` 的节点跳过 **前提条件**: - Binding 记录正确持久化 - 节点的 `binding_status` 正确保存和加载 - `compute_diff()` 逻辑准确 --- ## 下一步 详细的检查规范和状态转换规则,请参考: - [CHECK_SPEC.md](./CHECK_SPEC.md) - 检查点详细规范 - [STATE_TRANSITIONS.md](./STATE_TRANSITIONS.md) - 状态转换表