@@ -3,6 +3,7 @@ package restserver
33import (
44 "maps"
55 "net/http"
6+ "sync"
67 "time"
78
89 "github.com/Azure/azure-container-networking/cns"
@@ -124,7 +125,6 @@ func init() {
124125// Every http response is 200 so we really want cns response code.
125126// Hard tto do with middleware unless we derserialize the responses but making it an explit header works around it.
126127// if that doesn't work we could have a separate countervec just for response codes.
127-
128128func NewHandlerFuncWithHistogram (handler http.HandlerFunc , histogram * prometheus.HistogramVec ) http.HandlerFunc {
129129 return func (w http.ResponseWriter , req * http.Request ) {
130130 start := time .Now ()
@@ -157,14 +157,26 @@ type ipState struct {
157157 releasingIPs int64
158158}
159159
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 ()
160+ type asyncMetricsRecorder struct {
161+ podIPConfigSrc func () map [string ]cns.IPConfigurationStatus
162+ sig chan struct {}
163+ once sync.Once
164+ }
165+
166+ // singleton recorder
167+ var recorder asyncMetricsRecorder
168+
169+ // run starts the asyncMetricsRecorder and listens for signals to record the metrics.
170+ func (a * asyncMetricsRecorder ) run () {
171+ for range a .sig {
172+ a .record ()
173+ }
174+ }
165175
176+ // record records the IP Config state metrics to Prometheus.
177+ func (a * asyncMetricsRecorder ) record () {
166178 var state ipState
167- for ipConfig := range maps .Values (service . PodIPConfigState ) {
179+ for ipConfig := range maps .Values (a . podIPConfigSrc () ) {
168180 state .allocatedIPs ++
169181 if ipConfig .GetState () == types .Assigned {
170182 state .assignedIPs ++
@@ -195,3 +207,24 @@ func (service *HTTPRestService) publishIPStateMetrics() {
195207 pendingProgrammingIPCount .WithLabelValues (labels ... ).Set (float64 (state .programmingIPs ))
196208 pendingReleaseIPCount .WithLabelValues (labels ... ).Set (float64 (state .releasingIPs ))
197209}
210+
211+ // publishIPStateMetrics logs and publishes the IP Config state metrics to Prometheus.
212+ func (service * HTTPRestService ) publishIPStateMetrics () {
213+ recorder .once .Do (func () {
214+ recorder .podIPConfigSrc = service .PodIPConfigStates
215+ recorder .sig = make (chan struct {})
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