Skip to content

Commit a07cd62

Browse files
authored
make metrics recording async so that it will not block ip requests
Signed-off-by: Evan Baker <[email protected]>
1 parent bfb8bb4 commit a07cd62

File tree

1 file changed

+40
-7
lines changed

1 file changed

+40
-7
lines changed

cns/restserver/metrics.go

Lines changed: 40 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,6 @@ func init() {
124124
// Every http response is 200 so we really want cns response code.
125125
// Hard tto do with middleware unless we derserialize the responses but making it an explit header works around it.
126126
// if that doesn't work we could have a separate countervec just for response codes.
127-
128127
func NewHandlerFuncWithHistogram(handler http.HandlerFunc, histogram *prometheus.HistogramVec) http.HandlerFunc {
129128
return func(w http.ResponseWriter, req *http.Request) {
130129
start := time.Now()
@@ -157,14 +156,25 @@ type ipState struct {
157156
releasingIPs int64
158157
}
159158

160-
// publishIPStateMetrics logs and publishes the IP Config state metrics to Prometheus.
161-
func (service *HTTPRestService) publishIPStateMetrics() {
162-
// copy state
163-
service.RLock()
164-
defer service.RUnlock()
159+
type asyncMetricsRecorder struct {
160+
podIPConfigSrc func() map[string]cns.IPConfigurationStatus
161+
sig chan struct{}
162+
}
163+
164+
// singleton recorder
165+
var recorder *asyncMetricsRecorder
166+
167+
// run starts the asyncMetricsRecorder and listens for signals to record the metrics.
168+
func (a asyncMetricsRecorder) run() {
169+
for range a.sig {
170+
a.record()
171+
}
172+
}
165173

174+
// record records the IP Config state metrics to Prometheus.
175+
func (a asyncMetricsRecorder) record() {
166176
var state ipState
167-
for ipConfig := range maps.Values(service.PodIPConfigState) {
177+
for ipConfig := range maps.Values(a.podIPConfigSrc()) {
168178
state.allocatedIPs++
169179
if ipConfig.GetState() == types.Assigned {
170180
state.assignedIPs++
@@ -195,3 +205,26 @@ func (service *HTTPRestService) publishIPStateMetrics() {
195205
pendingProgrammingIPCount.WithLabelValues(labels...).Set(float64(state.programmingIPs))
196206
pendingReleaseIPCount.WithLabelValues(labels...).Set(float64(state.releasingIPs))
197207
}
208+
209+
// publishIPStateMetrics logs and publishes the IP Config state metrics to Prometheus.
210+
func (service *HTTPRestService) publishIPStateMetrics() {
211+
if recorder == nil {
212+
recorder = &asyncMetricsRecorder{
213+
podIPConfigSrc: service.PodIPConfigStates,
214+
sig: make(chan struct{}),
215+
}
216+
go recorder.run()
217+
}
218+
select {
219+
case recorder.sig <- struct{}{}: // signal the recorder to record the metrics
220+
default: // drop the signal if the recorder already has an event queued
221+
}
222+
}
223+
224+
// PodIPConfigStates returns a clone of the IP Config State map.
225+
func (service *HTTPRestService) PodIPConfigStates() map[string]cns.IPConfigurationStatus {
226+
// copy state
227+
service.RLock()
228+
defer service.RUnlock()
229+
return maps.Clone(service.PodIPConfigState)
230+
}

0 commit comments

Comments
 (0)