fix(gateway): close Phase 3C audit gaps
This commit is contained in:
@@ -90,6 +90,8 @@ func heartbeatLoop(ctx context.Context, client *gateway.ControlPlaneClient, serv
|
||||
ticker := time.NewTicker(2 * time.Second)
|
||||
defer ticker.Stop()
|
||||
var sequence int64
|
||||
var sampler heartbeatSampler
|
||||
_, _ = sampler.sample(time.Now(), server.Metrics())
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
@@ -104,11 +106,82 @@ func heartbeatLoop(ctx context.Context, client *gateway.ControlPlaneClient, serv
|
||||
state = "draining"
|
||||
}
|
||||
metrics := server.Metrics()
|
||||
_ = client.Heartbeat(ctx, protocol.GatewayHeartbeat{Version: "1", GatewayID: registration.GatewayID, Sequence: sequence, ObservedAt: time.Now().UTC().Format(time.RFC3339Nano), ActiveConnections: metrics.ActiveSessions, EgressKbps: registration.BandwidthCapacityKbps, State: state})
|
||||
observedAt := time.Now()
|
||||
egressKbps, telemetry := sampler.sample(observedAt, metrics)
|
||||
_ = client.Heartbeat(ctx, protocol.GatewayHeartbeat{
|
||||
Version: "1", GatewayID: registration.GatewayID, Sequence: sequence,
|
||||
ObservedAt: observedAt.UTC().Format(time.RFC3339Nano), ActiveConnections: metrics.ActiveSessions,
|
||||
EgressKbps: egressKbps, State: state, Telemetry: telemetry,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type heartbeatSampler struct {
|
||||
observedAt time.Time
|
||||
mediaBytes uint64
|
||||
}
|
||||
|
||||
func (s *heartbeatSampler) sample(observedAt time.Time, metrics gateway.MetricsSnapshot) (int64, protocol.GatewayTelemetry) {
|
||||
egressKbps := int64(0)
|
||||
elapsedMillis := observedAt.Sub(s.observedAt).Milliseconds()
|
||||
if !s.observedAt.IsZero() && elapsedMillis > 0 && metrics.MediaBytes >= s.mediaBytes {
|
||||
delta := metrics.MediaBytes - s.mediaBytes
|
||||
milliseconds := uint64(elapsedMillis)
|
||||
whole, remainder := delta/milliseconds, delta%milliseconds
|
||||
if whole > 125_000_000 {
|
||||
egressKbps = 1_000_000_000
|
||||
} else {
|
||||
rate := whole*8 + remainder*8/milliseconds
|
||||
if rate > 1_000_000_000 {
|
||||
rate = 1_000_000_000
|
||||
}
|
||||
egressKbps = int64(rate)
|
||||
}
|
||||
}
|
||||
s.observedAt, s.mediaBytes = observedAt, metrics.MediaBytes
|
||||
return egressKbps, protocol.GatewayTelemetry{
|
||||
AdmittedSessions: boundedMetric(metrics.AdmittedSessions), AdmissionRejects: boundedMetric(metrics.AdmissionRejects),
|
||||
Reconnects: boundedMetric(metrics.Reconnects), DrainTransitions: boundedMetric(metrics.DrainTransitions),
|
||||
MediaDrops: boundedMetric(metrics.MediaDrops), MediaPackets: boundedMetric(metrics.MediaPackets),
|
||||
MediaBytes: boundedMetric(metrics.MediaBytes), QueueDelayMicros: boundedMetric(metrics.QueueDelayNanos / 1000),
|
||||
ProcessingDelayMicros: boundedMetric(metrics.ProcessingDelayNanos / 1000), ProcessingSamples: boundedMetric(metrics.ProcessingSamples),
|
||||
PacingDelayMicros: boundedMetric(metrics.PacingDelayNanos / 1000), ProviderErrors: boundedMetric(metrics.ProviderErrors),
|
||||
InputRejected: boundedMetric(metrics.InputRejected), ControlRttMicros: boundedMetric(metrics.ControlRTTNanos / 1000),
|
||||
ControlJitterMicros: boundedMetric(metrics.ControlJitterNanos / 1000), ControlLossPpm: boundedMetric(metrics.ControlLossPPM),
|
||||
PendingReliable: boundedMetric(metrics.PendingReliable), ProviderState: providerStateName(metrics.ProviderState),
|
||||
}
|
||||
}
|
||||
|
||||
func boundedMetric(value uint64) int64 {
|
||||
const maximum = uint64(^uint64(0) >> 1)
|
||||
if value > maximum {
|
||||
return int64(maximum)
|
||||
}
|
||||
return int64(value)
|
||||
}
|
||||
|
||||
func providerStateName(value uint64) string {
|
||||
switch value {
|
||||
case 1:
|
||||
return gateway.ProviderStateStarting
|
||||
case 2:
|
||||
return gateway.ProviderStateReady
|
||||
case 3:
|
||||
return gateway.ProviderStateDisconnected
|
||||
case 4:
|
||||
return gateway.ProviderStateTerminating
|
||||
case 5:
|
||||
return gateway.ProviderStateTerminated
|
||||
case 6:
|
||||
return gateway.ProviderStateCleanup
|
||||
case 7:
|
||||
return gateway.ProviderStateFailed
|
||||
default:
|
||||
return "unknown"
|
||||
}
|
||||
}
|
||||
|
||||
func loadTLS(certFile, keyFile, clientCAFile string) (*tls.Config, *tls.Config, error) {
|
||||
certificate, err := tls.LoadX509KeyPair(certFile, keyFile)
|
||||
if err != nil {
|
||||
|
||||
Reference in New Issue
Block a user