fix(hop): respect backup metadata in priority shortcut selection
Priority short-circuit now checks for backup nodes before bypassing the selector. When any node has backup:true the selector (FailFilter, BackupFilter, strategy) runs instead, ensuring BackupFilter can separate primary from failover nodes. Previously backup was silently ignored when all nodes shared the same non-zero priority from matcher rule length.
This commit is contained in:
+27
-1
@@ -206,7 +206,15 @@ func (p *chainHop) Select(ctx context.Context, opts ...hop.SelectOption) *chain.
|
|||||||
return nodes[i].Options().Priority > nodes[j].Options().Priority
|
return nodes[i].Options().Priority > nodes[j].Options().Priority
|
||||||
})
|
})
|
||||||
|
|
||||||
if nodes[0].Options().Priority > 0 {
|
if nodes[0].Options().Priority > 0 &&
|
||||||
|
!anyBackupNode(nodes) {
|
||||||
|
// Priority short-circuit: highest-priority non-backup node wins.
|
||||||
|
// Conditions: (1) top priority > 0 means a matcher indicated routing
|
||||||
|
// specificity, so the top node is authoritative for this request;
|
||||||
|
// (2) no backup node is present, otherwise BackupFilter would be
|
||||||
|
// silently bypassed. When both hold the selector (FailFilter,
|
||||||
|
// BackupFilter, strategy) is skipped and the best node wins directly.
|
||||||
|
p.logger.Debugf("priority shortcut: node %s selected", nodes[0].Name)
|
||||||
return nodes[0]
|
return nodes[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -413,3 +421,21 @@ func (p *chainHop) Close() error {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// anyBackupNode reports whether any node in the list has the backup metadata
|
||||||
|
// flag set. Used to ensure that when backup nodes are in the candidate pool
|
||||||
|
// the priority short-circuit is disabled, forcing selection through the
|
||||||
|
// selector where BackupFilter can separate primary from failover nodes.
|
||||||
|
// Without this gate, nodes with equal non-zero priority (auto-assigned from
|
||||||
|
// matcher rule length) would skip BackupFilter entirely via the priority
|
||||||
|
// short-circuit at Select, making backup metadata a no-op.
|
||||||
|
func anyBackupNode(nodes []*chain.Node) bool {
|
||||||
|
for _, node := range nodes {
|
||||||
|
if md := node.Options().Metadata; md != nil && md.IsExists("backup") {
|
||||||
|
if md.Get("backup") == true {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user