修复一个因为项目双向更新更新导致第二次更新无法进行的问题

This commit is contained in:
strepsiades
2026-04-03 11:44:53 +08:00
parent f5729d5a18
commit aa31243bae
2 changed files with 152 additions and 4 deletions
@@ -1,3 +1,5 @@
import copy
from pydantic import BaseModel
from ...sync_system.strategy import DefaultSyncStrategy
@@ -65,13 +67,42 @@ class ProjectSyncStrategy(DefaultSyncStrategy[ProjectResponseBase]):
return payload
@staticmethod
def _snapshot_node(node):
# project 是一个很特殊的双向更新场景:
# 1. 先做一次 PULL,把远端 ic_plan_* 回填到本地;
# 2. 再做一次常规 PUSH,把本地其余字段推到远端。
#
# 但 prepare_update_for_direction -> e30_update_prepare 会校验
# source_node 当前仍然处于可进入更新准备的稳定态(S01)。
# 如果直接复用同一个真实节点作为两次 update 的 source,第一次
# 准备完成后真实节点的 action/status 已经变化,第二次就不再满足
# “source 仍在 S01”的前置条件,导致第二次更新被状态机拒绝。
#
# 这里复制一个只用于“提供源数据/源状态视图”的快照,让两次 update
# 都从各自的原始稳定态出发做判断;真正被推进到 S07 / 写入 payload
# 的仍然是目标侧真实节点,而不是这个 snapshot。
snapshot = copy.deepcopy(node)
if hasattr(snapshot, "sync_log"):
snapshot.sync_log = None
return snapshot
async def update_pair(self, local_node, remote_node, data_id_map=None):
updated_by_id = {}
# 注意:这两个 snapshot 只会在各自方向上充当 source_node。
# - PULL: source=remote_snapshot, target=local_node
# - PUSH: source=local_snapshot, target=remote_node
#
# 因此真实 project 节点的状态变更仍只发生在 target 节点上,
# 不会因为传入 snapshot 而把本体节点替换掉,也不会把本体节点的
# action/status/error/sync_log 写到 snapshot 上后丢失掉。
local_snapshot = self._snapshot_node(local_node)
remote_snapshot = self._snapshot_node(remote_node)
if self.domain_option.pull_group_plan_production_date:
pull_update = await self.prepare_update_for_direction(
local_node,
remote_node,
remote_snapshot,
UpdateDirection.PULL,
data_id_map,
include_fields=self._PULL_ONLY_FIELDS,
@@ -85,7 +116,7 @@ class ProjectSyncStrategy(DefaultSyncStrategy[ProjectResponseBase]):
if self.config.update_direction != UpdateDirection.NONE:
generic_update = await self.prepare_update_for_direction(
local_node,
local_snapshot,
remote_node,
self.config.update_direction,
data_id_map,