feat: add executable multiplayer SLO checks

This commit is contained in:
Josh Creek
2026-08-31 21:02:29 +01:00
parent 3dde0ffb79
commit c0d1c33f54
3 changed files with 98 additions and 1 deletions
+70
View File
@@ -0,0 +1,70 @@
package observability
import (
"sort"
"time"
)
type SLOWindow struct {
RegionalRTT []time.Duration
Assignment []time.Duration
Connection []time.Duration
APILatency []time.Duration
Matches []bool
TickBacklog bool
Headroom float64
}
type SLOViolation struct {
Metric string
Reason string
}
func EvaluateSLO(window SLOWindow) []SLOViolation {
violations := make([]SLOViolation, 0)
if percentile(window.RegionalRTT, .95) > 80*time.Millisecond {
violations = append(violations, SLOViolation{"regional_rtt_p95", "exceeds 80ms"})
}
if percentile(window.Assignment, .95) > 5*time.Second || percentile(window.Assignment, .99) > 10*time.Second {
violations = append(violations, SLOViolation{"assignment_latency", "p95/p99 threshold exceeded"})
}
if percentile(window.Connection, .95) > 5*time.Second {
violations = append(violations, SLOViolation{"connection_latency_p95", "exceeds 5s"})
}
if ratio(window.Matches) < .999 {
violations = append(violations, SLOViolation{"allocation_result_success", "below 99.9%"})
}
if percentile(window.APILatency, .95) > 250*time.Millisecond {
violations = append(violations, SLOViolation{"api_latency_p95", "exceeds 250ms"})
}
if window.TickBacklog {
violations = append(violations, SLOViolation{"tick_health", "physics backlog detected"})
}
if window.Headroom > 0 && window.Headroom < .30 {
violations = append(violations, SLOViolation{"resource_headroom", "below 30%"})
}
return violations
}
func percentile(values []time.Duration, p float64) time.Duration {
if len(values) == 0 {
return 0
}
ordered := append([]time.Duration(nil), values...)
sort.Slice(ordered, func(i, j int) bool { return ordered[i] < ordered[j] })
index := int(float64(len(ordered)-1) * p)
return ordered[index]
}
func ratio(values []bool) float64 {
if len(values) == 0 {
return 1
}
success := 0
for _, value := range values {
if value {
success++
}
}
return float64(success) / float64(len(values))
}
+27
View File
@@ -0,0 +1,27 @@
package observability
import (
"testing"
"time"
)
func TestEvaluateSLOAcceptsHealthyWindow(t *testing.T) {
window := SLOWindow{RegionalRTT: []time.Duration{20 * time.Millisecond, 40 * time.Millisecond}, Assignment: []time.Duration{time.Second}, Connection: []time.Duration{time.Second}, APILatency: []time.Duration{100 * time.Millisecond}, Matches: []bool{true, true, true}, Headroom: .50}
if violations := EvaluateSLO(window); len(violations) != 0 {
t.Fatalf("healthy window violations = %+v", violations)
}
}
func TestEvaluateSLOFlagsEveryLaunchGate(t *testing.T) {
window := SLOWindow{RegionalRTT: []time.Duration{101 * time.Millisecond}, Assignment: []time.Duration{11 * time.Second}, Connection: []time.Duration{6 * time.Second}, APILatency: []time.Duration{251 * time.Millisecond}, Matches: []bool{true, false}, TickBacklog: true, Headroom: .29}
violations := EvaluateSLO(window)
if len(violations) != 7 {
t.Fatalf("violations = %+v", violations)
}
}
func TestEvaluateSLODoesNotInventFailureForEmptyOptionalWindows(t *testing.T) {
if violations := EvaluateSLO(SLOWindow{}); len(violations) != 0 {
t.Fatalf("empty window violations = %+v", violations)
}
}