Files

8.5 KiB
Raw Permalink Blame History

同步流程(pipeline -> strategy -> datasource

1. 全流程主线

  1. pipeline 装配组件并加载持久化。
  2. pipeline 为 datasource 绑定 collection,但不在 bootstrap 阶段全量拉取业务数据。
  3. pipeline 在每个 node_type 开始执行前,单独加载该 node_type 的最新数据。
  4. pipeline 调用 strategy.bind()
  5. pipeline 调用 strategy.create() / strategy.update() 生成动作节点。
  6. pipeline 调用 datasource.sync_all() 执行动作并回写执行状态。
  7. pipeline 输出统计并持久化。

2. reset 时序

2.1 加载时恢复

  • sync_state_machine/common/collection.py::load_from_persistence() 执行。
  • 语义:仅恢复持久化状态,并记录本轮 sync_logpersistence 恢复来源;不在此阶段做状态归并。
  • 恢复后保留 data/origin_data,等待 bootstrap 阶段的 datasource 刷新覆盖最新数据。

2.2 bootstrap datasource refresh

  • pipeline 在持久化恢复后、E01 之前,按已恢复到内存的 node_type 做一次 datasource 刷新。
  • 实际实现:sync_state_machine/pipeline/full_sync_pipeline.py::_bootstrap_refresh_latest_data()
  • 语义:
    • 如果 datasource 命中节点,则用最新数据覆盖持久化快照,并清除 _loaded_from_persistence 标记。
    • 如果 datasource 未命中节点,则节点保留持久化快照,供 E01 判断它是 stale zombie 还是 bootstrap 异常隔离对象。

2.3 加载后 cleanup

  • pipeline 在 datasource refresh 完成后调用 run_phase2_cleanup()
  • 实际实现:sync_state_machine/sync_system/strategy_ops/reset_ops.py::run_phase2_cleanup()
  • 核心事件:E01S16 -> S00/S15)。
  • S16 表示“bootstrap 输入态”:持久化恢复出的节点,叠加 datasource refresh 后仍待 E01 判定的节点集合。
  • 判定:
    • is_create_zombie=true -> S15,节点删除(并尝试解绑);
    • bootstrap_source_present=false && has_binding_record=false -> S15,说明该节点仅残留在 persistence 中且未绑定,按 stale zombie 清理;
    • bootstrap_source_present=false && has_binding_record=true -> S17,说明该节点存在绑定,但 datasource refresh 未返回,进入 bootstrap 加载异常隔离;
    • 其余情况 -> S00,节点归并为 UNCHECKED/NONE/PENDING 并清空 error

2.2.1 enable_persistence 与 bootstrap 关系

  • enable_persistence=true:先 load_from_persistence(),再做 bootstrap datasource refresh,最后对输入节点执行 E01S16 域内处理)。
  • enable_persistence=false:本轮没有持久化输入,S16/E01 不参与;随后 Stage1 新加载节点直接进入本轮 bind/create/update/sync 主流程。

2.4 加载异常隔离(S17

  • 持久化中若出现非法枚举值(action/status/binding_status),节点标记为 bootstrap_blockedS17 语义)。
  • 持久化恢复后若节点存在绑定,但 bootstrap datasource refresh 未返回该节点,也会进入 S17 语义并隔离。
  • 这类节点保留 error,用于人工排查。
  • 这类节点不会进入 E01,也不会参与 bind/create/update/sync 自动流程。

3. bind 流程(strategy_ops

  • 入口:sync_state_machine/sync_system/strategy.py::DefaultSyncStrategy.bind()
  • 入口状态:S00

bind 编排步骤

  • strategy 先通过 bind_ops.collect_bind_entry_nodes() 收集两侧 S00 节点,作为 bind 入口工作集。
  • phase_core_state() 对入口工作集触发 E10,把“已有绑定记录”和“无绑定记录”的节点分流到 S01/S03/S04/S02
  • phase_dependency_check() 对仍需继续处理的缺绑节点触发 E15,把缺数据、依赖不满足、语义错误的节点拦到 S03/S05/S04
  • strategy 再通过 bind_ops.collect_auto_bind_ready_nodes() 收窄工作集,只保留当前 S02 + binding_status=MISSING 的节点进入自动绑定判定。
  • strategy 在顶层显式构造 orphan create 控制参数,并传给 bind_ops.plan_auto_bind_updates() 生成自动绑定/自动创建决策。
  • apply_auto_bind_updates() 对这些决策逐个触发 E16,把节点迁移到 S01/S04/S05/S13
  • refresh_bind_data_id() 最后按绑定关系回填两侧节点的 context.bind_data_id

核心绑定判定

  • phase_core_state() 内触发 E10
  • 有绑定记录:根据本端/对端有效性进入 S01/S03/S04
  • 无绑定记录:进入 S02

注意:如果节点在 bootstrap 阶段已被隔离为 S17 语义(bootstrap_blocked=true),默认不会进入 bind 工作集。

依赖检查

  • phase_dependency_check() -> check_dependencies_for_nodes() 内触发 E15
  • data_present=truedep_satisfied=true -> 不迁移,节点保持在 S02,继续进入自动绑定判定。
  • data_present=false -> S03
  • dep_satisfied=false -> S05
  • depend_fields 为空本身不会触发阻断;若节点数据存在,则等价于“当前依赖满足”,继续留在 S02

自动绑定

  • phase_auto_binding() 内触发 E16
  • ONE_TO_ONE -> S01AMBIGUOUS/KEY_MISSING/DATA_MISSING -> S04KEY_ID_RESOLVE_FAIL -> S05
  • ZERO + create_enabled=true -> S13PEER_CREATING/NONE/PENDING,待对侧创建中间态);ZERO + create_enabled=false -> S04
  • auto_bind=false 时,E16 直接落 S04(自动绑定未启用),不会进入自动创建路径。

4. create/update 准备

create

  • 入口:sync_state_machine/sync_system/strategy.py::DefaultSyncStrategy.create()
  • 运行时事件:E20E21/E22 为配置保留分支,当前 strategy 未接入自动执行)
  • 运行时入口状态:S13
  • 说明:E16 负责识别“需自动创建”并将源节点置为 S13;业务代码执行对侧 spawn+bind 后,再通过 E20S13 提交到 S01(成功);若 spawn 失败,E20 不迁移并保留在 S13 等待人工/重试。
  • data_id 约束:
    • S13/S01 要求源节点 data_id 存在(data_id_exist=true)。
    • 新创建目标节点在 S06/S10C 阶段允许 data_id 为空;CREATE SUCCESSS11C)必须携带非空 result_data_id,否则事件直接报错。

update

  • 入口:sync_state_machine/sync_system/strategy.py::DefaultSyncStrategy.update()
  • 事件:E30
  • 入口状态(source 节点):S01
  • target_has_data_id=falseupdate_id_resolve_ok=false -> S08
  • has_diff=true -> S07

post-create 归并

  • 入口:sync_state_machine/pipeline/full_sync_pipeline.py::normalize_create_success_to_update_entry()
  • 事件:E41
  • 语义:CREATE 执行成功后,节点先落 S11CSUCCESS),再归并 S11C -> S01,作为同轮 update 起点。

5. 执行回写(datasource

  • 入口:sync_state_machine/datasource/datasource.py
  • 事件:E40C_START/E40CE40U_START/E40UE40D_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 运行时只处理 S13E20 提交,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. 不变量保障

  • 每次事件落地后,sync_state_machine/engine/events.py::_apply_decision() 会执行 runtime.check_invariants()
  • 违反 invariant 直接抛错,终止当前路径。