Expose QUIC fabric capacity pressure

This commit is contained in:
2026-05-16 12:46:36 +03:00
parent 5c02667398
commit 28c26a5103
3 changed files with 30 additions and 7 deletions
@@ -51,6 +51,9 @@ type QUICFabricTransportSnapshot struct {
SchemaVersion string `json:"schema_version"` SchemaVersion string `json:"schema_version"`
ActiveCount int `json:"active_count"` ActiveCount int `json:"active_count"`
ActiveStreams int `json:"active_streams"` ActiveStreams int `json:"active_streams"`
MaxStreamsPerConn int `json:"max_streams_per_conn"`
SaturatedConnections int `json:"saturated_connections"`
CapacityPressurePercent int `json:"capacity_pressure_percent"`
Stats QUICFabricTransportStats `json:"stats"` Stats QUICFabricTransportStats `json:"stats"`
} }
@@ -334,8 +337,13 @@ func (t *QUICFabricTransport) Snapshot() QUICFabricTransportSnapshot {
t.mu.Lock() t.mu.Lock()
defer t.mu.Unlock() defer t.mu.Unlock()
t.pruneIdleLocked(time.Now()) t.pruneIdleLocked(time.Now())
limit := t.MaxStreamsPerConn
if limit <= 0 {
limit = defaultQUICFabricMaxStreamsPerConn
}
snapshot := QUICFabricTransportSnapshot{ snapshot := QUICFabricTransportSnapshot{
SchemaVersion: "rap.quic_fabric_transport.v1", SchemaVersion: "rap.quic_fabric_transport.v1",
MaxStreamsPerConn: limit,
Stats: t.stats, Stats: t.stats,
} }
for key, entry := range t.conns { for key, entry := range t.conns {
@@ -350,6 +358,15 @@ func (t *QUICFabricTransport) Snapshot() QUICFabricTransportSnapshot {
default: default:
snapshot.ActiveCount++ snapshot.ActiveCount++
snapshot.ActiveStreams += entry.activeStreams snapshot.ActiveStreams += entry.activeStreams
if entry.activeStreams >= limit {
snapshot.SaturatedConnections++
}
}
}
if snapshot.ActiveCount > 0 && limit > 0 {
capacity := snapshot.ActiveCount * limit
if capacity > 0 {
snapshot.CapacityPressurePercent = (snapshot.ActiveStreams * 100) / capacity
} }
} }
return snapshot return snapshot
@@ -267,7 +267,11 @@ func TestQUICFabricTransportLimitsStreamsPerConnection(t *testing.T) {
t.Fatal("second connect succeeded past stream limit") t.Fatal("second connect succeeded past stream limit")
} }
snapshot := transport.Snapshot() snapshot := transport.Snapshot()
if snapshot.ActiveStreams != 1 || snapshot.Stats.StreamLimitRejects != 1 { if snapshot.ActiveStreams != 1 ||
snapshot.MaxStreamsPerConn != 1 ||
snapshot.SaturatedConnections != 1 ||
snapshot.CapacityPressurePercent != 100 ||
snapshot.Stats.StreamLimitRejects != 1 {
t.Fatalf("unexpected stream limit snapshot: %+v", snapshot) t.Fatalf("unexpected stream limit snapshot: %+v", snapshot)
} }
if err := first.Close(); err != nil { if err := first.Close(); err != nil {
@@ -416,6 +416,8 @@ gateway status.
Receive-side fabric-session packet counters are reported by traffic class and Receive-side fabric-session packet counters are reported by traffic class and
stream id as well, so gateway status can compare TX and RX distribution under stream id as well, so gateway status can compare TX and RX distribution under
browser/RDP load. browser/RDP load.
QUIC fabric transport snapshots expose the configured stream limit, saturated
connection count, and capacity pressure percentage next to stream limit rejects.
Endpoint ranking treats `capacity_limited` observations as a soft pressure Endpoint ranking treats `capacity_limited` observations as a soft pressure
penalty instead of a hard recent failure, enabling load spreading without penalty instead of a hard recent failure, enabling load spreading without
marking the carrier unhealthy. marking the carrier unhealthy.