diff --git a/pkg/monitoring/collector.go b/pkg/monitoring/collector.go index aafe334f..0a79be36 100644 --- a/pkg/monitoring/collector.go +++ b/pkg/monitoring/collector.go @@ -53,7 +53,9 @@ type basicCollector struct { logger logr.Logger } +// only use with Lock called before func (c *basicCollector) clearChannels() { + defer c.mu.Unlock() c.channels = []chan<- prometheus.Metric{} } func (d *typedFactoryDesc) mustNewConstMetric(value float64, labels ...string) prometheus.Metric { diff --git a/pkg/monitoring/frr.go b/pkg/monitoring/frr.go index 62bdcc3b..e3f9ed0d 100644 --- a/pkg/monitoring/frr.go +++ b/pkg/monitoring/frr.go @@ -253,18 +253,22 @@ func (c *frrCollector) Update(ch chan<- prometheus.Metric) error { if len(c.channels) == 1 { c.wg = sync.WaitGroup{} c.wg.Add(1) - go func() { - defer c.wg.Done() - vrfs := c.getVrfs() - neighbors := c.getBGPNeighbors() - routes := c.getRoutes() + // Ensure all other function calls will wait + c.mu.Unlock() + routes, neighbors, vrfs := func() ([]route.Information, frr.BGPVrfSummary, []frr.VrfVniSpec) { + return c.getRoutes(), c.getBGPNeighbors(), c.getVrfs() + }() + go func(routes []route.Information, neighbors frr.BGPVrfSummary, vrfs []frr.VrfVniSpec) { c.mu.Lock() - defer c.mu.Unlock() + // unlock is done after return using defer + defer c.wg.Done() c.updateChannels(vrfs, routes, neighbors) - c.clearChannels() - }() + }(routes, neighbors, vrfs) + // unlock is done in this function. + defer c.clearChannels() + } else { + c.mu.Unlock() } - c.mu.Unlock() c.wg.Wait() return nil } diff --git a/pkg/monitoring/nl.go b/pkg/monitoring/nl.go index 3c7b15fe..8a140e6d 100644 --- a/pkg/monitoring/nl.go +++ b/pkg/monitoring/nl.go @@ -93,17 +93,22 @@ func (c *netlinkCollector) Update(ch chan<- prometheus.Metric) error { if len(c.channels) == 1 { c.wg = sync.WaitGroup{} c.wg.Add(1) - go func() { - defer c.wg.Done() - routes := c.getRoutes() - neighbors := c.getNeighbors() + // Ensure all other function calls will wait + c.mu.Unlock() + routes, neighbors := func() ([]route.Information, []nl.NeighborInformation) { + return c.getRoutes(), c.getNeighbors() + }() + go func(routes []route.Information, neighbors []nl.NeighborInformation) { c.mu.Lock() - defer c.mu.Unlock() + // unlock is done after return using defer + defer c.wg.Done() c.updateChannels(neighbors, routes) - c.clearChannels() - }() + }(routes, neighbors) + // unlock is done in this function. + defer c.clearChannels() + } else { + c.mu.Unlock() } - c.mu.Unlock() c.wg.Wait() return nil }