diff --git a/kernel/api/transaction.go b/kernel/api/transaction.go index b39cd32d1..1aebcbff0 100644 --- a/kernel/api/transaction.go +++ b/kernel/api/transaction.go @@ -98,6 +98,16 @@ func pushTransactions(app, session string, transactions []*model.Transaction) { evt.AppId = app evt.SessionId = session evt.Data = transactions + + var rootIDs []string + for _, tx := range transactions { + rootIDs = append(rootIDs, tx.GetChangedRootIDs()...) + } + rootIDs = gulu.Str.RemoveDuplicatedElem(rootIDs) + evt.Context = map[string]any{ + "rootIDs": rootIDs, + } + for _, tx := range transactions { tx.WaitForCommit() } diff --git a/kernel/model/push_reload.go b/kernel/model/push_reload.go index a5a093073..08dae774d 100644 --- a/kernel/model/push_reload.go +++ b/kernel/model/push_reload.go @@ -276,14 +276,25 @@ func refreshDynamicRefText(updatedDefNode *ast.Node, updatedTree *parse.Tree) { // refreshDynamicRefTexts 用于批量刷新块引用的动态锚文本。 // 该实现依赖了数据库缓存,导致外部调用时可能需要阻塞等待数据库写入后才能获取到 refs -func refreshDynamicRefTexts(updatedDefNodes map[string]*ast.Node, updatedTrees map[string]*parse.Tree) { +func refreshDynamicRefTexts(updatedDefNodes map[string]*ast.Node, updatedTrees map[string]*parse.Tree) (changedRootIDs []string) { + for t := range updatedTrees { + changedRootIDs = append(changedRootIDs, t) + } + for i := 0; i < 7; i++ { updatedRefNodes, updatedRefTrees := refreshDynamicRefTexts0(updatedDefNodes, updatedTrees) if 1 > len(updatedRefNodes) { break } updatedDefNodes, updatedTrees = updatedRefNodes, updatedRefTrees + + for t := range updatedTrees { + changedRootIDs = append(changedRootIDs, t) + } } + + changedRootIDs = gulu.Str.RemoveDuplicatedElem(changedRootIDs) + return } func refreshDynamicRefTexts0(updatedDefNodes map[string]*ast.Node, updatedTrees map[string]*parse.Tree) (updatedRefNodes map[string]*ast.Node, updatedRefTrees map[string]*parse.Tree) { diff --git a/kernel/model/transaction.go b/kernel/model/transaction.go index 40581502e..c6c6de6bd 100644 --- a/kernel/model/transaction.go +++ b/kernel/model/transaction.go @@ -1841,9 +1841,10 @@ type Transaction struct { DoOperations []*Operation `json:"doOperations"` UndoOperations []*Operation `json:"undoOperations"` - trees map[string]*parse.Tree // 事务中变更的树 - nodes map[string]*ast.Node // 事务中变更的节点 - relatedAvIDs []string // 事务中变更的属性视图 ID + trees map[string]*parse.Tree // 事务中变更的树 + nodes map[string]*ast.Node // 事务中变更的节点 + relatedAvIDs []string // 事务中变更的属性视图 ID + changedRootIDs []string // 变更的树 ID 列表(包含了变更定义块后影响的动态锚文本所在的树) isGlobalAssetsInit bool // 是否初始化过全局资源判断 isGlobalAssets bool // 是否属于全局资源 @@ -1854,6 +1855,18 @@ type Transaction struct { state atomic.Int32 // 0: 初始化,1:未提交,:2: 已提交,3: 已回滚 } +func (tx *Transaction) GetChangedRootIDs() (ret []string) { + for t := range tx.trees { + ret = append(ret, t) + } + + for _, id := range tx.changedRootIDs { + ret = append(ret, id) + } + ret = gulu.Str.RemoveDuplicatedElem(ret) + return +} + func (tx *Transaction) WaitForCommit() { for { if 1 == tx.state.Load() { @@ -1885,7 +1898,7 @@ func (tx *Transaction) commit() (err error) { checkUpsertInUserGuide(tree) } - refreshDynamicRefTexts(tx.nodes, tx.trees) + tx.changedRootIDs = refreshDynamicRefTexts(tx.nodes, tx.trees) tx.relatedAvIDs = gulu.Str.RemoveDuplicatedElem(tx.relatedAvIDs) for _, avID := range tx.relatedAvIDs { diff --git a/kernel/util/result.go b/kernel/util/result.go index 3ed4ac394..7789a1f7d 100644 --- a/kernel/util/result.go +++ b/kernel/util/result.go @@ -33,15 +33,16 @@ const ( ) type Result struct { - Cmd string `json:"cmd"` - ReqId float64 `json:"reqId"` - AppId string `json:"app"` - SessionId string `json:"sid"` - PushMode PushMode `json:"pushMode"` - Callback interface{} `json:"callback"` - Code int `json:"code"` - Msg string `json:"msg"` - Data interface{} `json:"data"` + Cmd string `json:"cmd"` + ReqId float64 `json:"reqId"` + AppId string `json:"app"` + SessionId string `json:"sid"` + PushMode PushMode `json:"pushMode"` + Callback interface{} `json:"callback"` + Code int `json:"code"` + Msg string `json:"msg"` + Data interface{} `json:"data"` + Context map[string]any `json:"context,omitempty"` } func NewResult() *Result {