diff --git a/common/monitoring/monitoring.go b/common/monitoring/monitoring.go index ca21056b..91dbd417 100644 --- a/common/monitoring/monitoring.go +++ b/common/monitoring/monitoring.go @@ -30,6 +30,7 @@ import ( "context" "fmt" "net/http" + "sync/atomic" "time" "github.com/AliceO2Group/Control/common/logger" @@ -38,8 +39,8 @@ import ( ) var ( - // scraping endpoint implementation - server *http.Server + // atomic holder for the HTTP server instance + server atomic.Pointer[http.Server] // objects to store incoming metrics metricsInternal *MetricsAggregate metricsHistogramInternal *MetricsReservoirSampling @@ -154,33 +155,30 @@ func handleFunc(endpointName string) { // // If we attempt send more messages than the size of the buffer, these overflowing messages will be ignored and warning will be logged. func Run(port uint16, endpointName string) error { - if IsRunning() { + localServer := &http.Server{Addr: fmt.Sprintf(":%d", port)} + // only one Run should initialize and serve + if !server.CompareAndSwap(nil, localServer) { return nil } - initChannels() - go eventLoop() - - server = &http.Server{Addr: fmt.Sprintf(":%d", port)} handleFunc(endpointName) - return server.ListenAndServe() + // block until Shutdown is called + return localServer.ListenAndServe() } func Stop() { - if !IsRunning() { + localServer := server.Swap(nil) + if localServer == nil { return } - ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() - server.Shutdown(ctx) - + localServer.Shutdown(ctx) endChannel <- struct{}{} <-endChannel - server = nil } func IsRunning() bool { - return server != nil + return server.Load() != nil } diff --git a/common/monitoring/monitoring_test.go b/common/monitoring/monitoring_test.go index 67540d0f..b0da3843 100644 --- a/common/monitoring/monitoring_test.go +++ b/common/monitoring/monitoring_test.go @@ -81,20 +81,12 @@ func TestStartMultipleStop(t *testing.T) { Stop() } -func cleaningUpAfterTest() { - Stop() -} - -func initTest() { - go Run(12345, "notimportant") -} - // decorator function that properly inits and cleans after higher level test of Monitoring package func testFunction(t *testing.T, testToRun func(*testing.T)) { - initTest() + go Run(12345, "notimportant") isRunningWithTimeout(t, time.Second) testToRun(t) - cleaningUpAfterTest() + Stop() } func TestSendingSingleMetric(t *testing.T) {