Skip to content

Commit

Permalink
make metrics recording async so that it will not block ip requests
Browse files Browse the repository at this point in the history
Signed-off-by: Evan Baker <rbtr@users.noreply.github.com>
  • Loading branch information
rbtr authored Oct 14, 2024
1 parent bfb8bb4 commit a07cd62
Showing 1 changed file with 40 additions and 7 deletions.
47 changes: 40 additions & 7 deletions cns/restserver/metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,6 @@ func init() {
// Every http response is 200 so we really want cns response code.
// Hard tto do with middleware unless we derserialize the responses but making it an explit header works around it.
// if that doesn't work we could have a separate countervec just for response codes.

func NewHandlerFuncWithHistogram(handler http.HandlerFunc, histogram *prometheus.HistogramVec) http.HandlerFunc {
return func(w http.ResponseWriter, req *http.Request) {
start := time.Now()
Expand Down Expand Up @@ -157,14 +156,25 @@ type ipState struct {
releasingIPs int64
}

// publishIPStateMetrics logs and publishes the IP Config state metrics to Prometheus.
func (service *HTTPRestService) publishIPStateMetrics() {
// copy state
service.RLock()
defer service.RUnlock()
type asyncMetricsRecorder struct {
podIPConfigSrc func() map[string]cns.IPConfigurationStatus
sig chan struct{}
}

// singleton recorder
var recorder *asyncMetricsRecorder

// run starts the asyncMetricsRecorder and listens for signals to record the metrics.
func (a asyncMetricsRecorder) run() {
for range a.sig {
a.record()
}
}

// record records the IP Config state metrics to Prometheus.
func (a asyncMetricsRecorder) record() {
var state ipState
for ipConfig := range maps.Values(service.PodIPConfigState) {
for ipConfig := range maps.Values(a.podIPConfigSrc()) {
state.allocatedIPs++
if ipConfig.GetState() == types.Assigned {
state.assignedIPs++
Expand Down Expand Up @@ -195,3 +205,26 @@ func (service *HTTPRestService) publishIPStateMetrics() {
pendingProgrammingIPCount.WithLabelValues(labels...).Set(float64(state.programmingIPs))
pendingReleaseIPCount.WithLabelValues(labels...).Set(float64(state.releasingIPs))
}

// publishIPStateMetrics logs and publishes the IP Config state metrics to Prometheus.
func (service *HTTPRestService) publishIPStateMetrics() {
if recorder == nil {
recorder = &asyncMetricsRecorder{
podIPConfigSrc: service.PodIPConfigStates,
sig: make(chan struct{}),
}
go recorder.run()
}
select {
case recorder.sig <- struct{}{}: // signal the recorder to record the metrics
default: // drop the signal if the recorder already has an event queued
}
}

// PodIPConfigStates returns a clone of the IP Config State map.
func (service *HTTPRestService) PodIPConfigStates() map[string]cns.IPConfigurationStatus {
// copy state
service.RLock()
defer service.RUnlock()
return maps.Clone(service.PodIPConfigState)
}

0 comments on commit a07cd62

Please sign in to comment.