Feed VPN fabric endpoint health into ranking

This commit is contained in:
2026-05-16 11:04:56 +03:00
parent e185e1f142
commit 396d36d5a9
6 changed files with 169 additions and 1 deletions
@@ -206,7 +206,7 @@ func scoreEndpointCandidateObservation(observation EndpointCandidateHealthObserv
case observation.LastLatencyMs > 0 && observation.LastLatencyMs <= 50:
score += 18
reasons = append(reasons, "latency:low")
case observation.LastLatencyMs <= 150:
case observation.LastLatencyMs > 0 && observation.LastLatencyMs <= 150:
score += 8
reasons = append(reasons, "latency:moderate")
case observation.LastLatencyMs > 0:
@@ -307,6 +307,52 @@ func TestRankPeerEndpointCandidatesTreatsStaleObservationAsPenalty(t *testing.T)
}
}
func TestRankPeerEndpointCandidatesDoesNotRewardZeroLatencyFailure(t *testing.T) {
now := time.Date(2026, 5, 16, 12, 0, 0, 0, time.UTC)
ranked := RankPeerEndpointCandidates([]PeerEndpointCandidate{
{
EndpointID: "node-b-quic",
NodeID: "node-b",
Transport: "direct_quic",
Address: "quic://node-b.example.test:19443",
Reachability: "public",
ConnectivityMode: "direct",
Priority: 10,
LastVerifiedAt: &now,
},
{
EndpointID: "node-b-wss",
NodeID: "node-b",
Transport: "wss",
Address: "https://node-b.example.test:443",
Reachability: "public",
ConnectivityMode: "direct",
Priority: 10,
LastVerifiedAt: &now,
},
}, EndpointCandidateScoreOptions{
ChannelClass: SyntheticChannelFabricControl,
Now: now,
MaxVerificationAge: time.Minute,
Observations: map[string]EndpointCandidateHealthObservation{
"node-b-quic": {
EndpointID: "node-b-quic",
FailureCount: 2,
LastFailureReason: "session_open_failed",
ReliabilityScore: 35,
ObservedAt: now,
},
},
MaxObservationAge: time.Minute,
})
if ranked[0].Candidate.EndpointID != "node-b-wss" {
t.Fatalf("top endpoint = %q, want wss after repeated quic failures: %+v", ranked[0].Candidate.EndpointID, ranked)
}
if containsReason(ranked[1].Reasons, "latency:moderate") {
t.Fatalf("zero latency failure was rewarded as moderate latency: %+v", ranked[1].Reasons)
}
}
func containsReason(reasons []string, reason string) bool {
for _, item := range reasons {
if item == reason {
@@ -25,6 +25,7 @@ type FabricTransport interface {
}
type FabricTransportTarget struct {
EndpointID string
PeerID string
Endpoint string
Transport string