# 同步流程(pipeline -> strategy -> datasource) ## 1. 全流程主线 1. pipeline 装配组件并加载持久化。 2. pipeline 调用 `strategy.bind()`。 3. pipeline 调用 `strategy.create()` / `strategy.update()` 生成动作节点。 4. pipeline 调用 `datasource.sync_all()` 执行动作并回写执行状态。 5. pipeline 输出统计并持久化。 ## 2. reset 时序 ### 2.1 加载时 reset(phase1 语义) - 在 `common/collection.py::load_from_persistence()` 执行。 - 语义:仅恢复持久化状态(不在此阶段做状态归并)。 ### 2.2 加载后 cleanup(phase2 语义) - pipeline 调用 `BaseSyncStrategy.run_reset()`。 - 实际实现:`strategy_ops/reset_ops.py::run_phase2_cleanup()`。 - 核心事件:`E01`(`S16 -> S00/S15`)。 - `S16` 表示“持久化加载输入态”:本轮从持久化恢复出的节点集合(可包含上轮遗留节点,也可包含上轮已稳定节点)。 - 判定: - `is_create_zombie=true` -> `S15`,节点删除(并尝试解绑); - `is_create_zombie=false` -> `S00`,节点归并为 `UNCHECKED/NONE/PENDING` 并清空 `error`。 ### 2.2.1 `enable_persistence` 与 bootstrap 关系 - `enable_persistence=true`:先 `load_from_persistence()`,再对加载出的节点执行 `E01`(`S16` 域内处理)。 - `enable_persistence=false`:本轮没有持久化输入,`S16/E01` 不参与;随后 Stage1 新加载节点直接进入本轮 bind/create/update/sync 主流程。 ### 2.3 加载异常隔离(S17) - 持久化中若出现非法枚举值(`action/status/binding_status`),节点标记为 `bootstrap_blocked`(`S17` 语义)。 - 这类节点保留 `error`,用于人工排查。 - 这类节点不会进入 `E01`,也不会参与 bind/create/update/sync 自动流程。 ## 3. bind 流程(strategy_ops) - 入口:`strategy_ops/bind_ops.py::run_bind()` - 入口状态:`S00` ### 核心绑定判定 - `phase_core_state()` 内触发 `E10`。 - 有绑定记录:根据本端/对端有效性进入 `S01/S03/S04`。 - 无绑定记录:进入 `S02`。 ### 依赖检查 - `phase_dependency_check()` -> `check_dependencies_for_nodes()` 内触发 `E15`。 - `data_present=false` -> `S03`。 - `dep_satisfied=false` -> `S05`。 - `depend_fields` 为空 -> `S04`(无法自动处理,阻断后续自动创建)。 ### 自动绑定 - `phase_auto_binding()` 内触发 `E16`。 - `ONE_TO_ONE` -> `S01`;`AMBIGUOUS/KEY_MISSING/DATA_MISSING` -> `S04`;`KEY_ID_RESOLVE_FAIL` -> `S05`。 - `ZERO + create_enabled=true` -> `S13`(`PEER_CREATING/NONE/PENDING`,待对侧创建中间态);`ZERO + create_enabled=false` -> `S04`。 - `auto_bind=false` 时,`E16` 直接落 `S04`(自动绑定未启用),不会进入自动创建路径。 ## 4. create/update 准备 ### create - 入口:`strategy_ops/create_ops.py::run_create()` - 运行时事件:`E20`(`E21/E22` 为配置保留分支,当前 strategy 未接入自动执行) - 运行时入口状态:`S13` - 说明:`E16` 负责识别“需自动创建”并将源节点置为 `S13`;业务代码执行对侧 spawn+bind 后,再通过 `E20` 将 `S13` 提交到 `S01`(成功);若 spawn 失败,`E20` 不迁移并保留在 `S13` 等待人工/重试。 - `data_id` 约束: - `S13/S01` 要求源节点 `data_id` 存在(`data_id_exist=true`)。 - 新创建目标节点在 `S06/S10C` 阶段允许 `data_id` 为空;`CREATE SUCCESS`(`S11C`)必须携带非空 `result_data_id`,否则事件直接报错。 ### update - 入口:`strategy_ops/update_ops.py::run_update()` - 事件:`E30` - 入口状态(source 节点):`S01` - `target_has_data_id=false` 或 `update_id_resolve_ok=false` -> `S08` - `has_diff=true` -> `S07` ### post-create 归并 - 入口:`pipeline/full_sync_pipeline.py::normalize_create_success_to_update_entry()` - 事件:`E41` - 语义:`CREATE` 执行成功后,节点先落 `S11C`(SUCCESS),再归并 `S11C -> S01`,作为同轮 update 起点。 ## 5. 执行回写(datasource) - 入口:`datasource/datasource.py` - 事件:`E40C_START/E40C`、`E40U_START/E40U`、`E40D_START/E40D` - 当前约束:delete stage 尚未接入 strategy 主流程;若运行时检测到 `S09/DELETE` 节点,DataSource 会显式抛错阻断(避免散落删除执行)。 - 执行准备入口状态: - `CREATE`: `S06` - `UPDATE`: `S07` - `DELETE`: `S09` - `S10` 为执行中状态(由本轮执行产生),执行流转固定为“入口 -> S10 -> 终态”,不再出现入口直接到成功/失败。 - 结果: - `SUCCESS -> S11C | S11U | S11D`(按动作) - `FAILED -> S12C | S12U | S12D`(按动作) - `IN_PROGRESS -> S10C | S10U | S10D`(按动作,支持异步 polling 闭环) - `SKIPPED + action=UPDATE -> S14` ## 6. 各阶段入口状态总表 | 阶段 | 入口状态 | 说明 | |---|---|---| | Reset(E01) | `S16` | create_zombie -> `S15`;其余 -> `S00` | | Bind(E10/E15/E16) | `S00` | bind 三段统一从 `S00` 进入 | | Create Prepare(E20/E21/E22) | `S02` / `S13` | 配置入口含 `S02/S13`;当前 strategy 运行时只处理 `S13` 的 `E20` 提交,`S02` 分支保留未接入 | | Post-create Ready(E41) | `S11C` | `CREATE` 成功节点归并到 `S01`,进入同轮 update | | Update Prepare(E30) | `S01` | 仅从 NORMAL 继续判定(create 成功先经 E41 归并) | | Sync Execute(E40C/U/D) | `S06` / `S07` / `S09` / `S10C` / `S10U` / `S10D` | 执行与回写:按动作分事件;入口先进入 `S10*`,再由 `S10*` 进入 `S11*`/`S12*`;轮询返回 `IN_PROGRESS` 时只记录任务进度,不新增状态迁移;仅 UPDATE 可走 `S14` | | 隔离(人工) | `S17` | 不参与自动阶段,仅人工处理 | ## 7. 不变量保障 - 每次事件落地后,`engine/events.py::_apply_decision()` 会执行 `runtime.check_invariants()`。 - 违反 invariant 直接抛错,终止当前路径。