fix(admin-monitor): fix a data race in the admin monitor EE-2761 (#6658)

pull/6596/merge
andres-portainer 3 years ago committed by GitHub
parent f63b07bbb9
commit ecf5e90783
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -3,6 +3,7 @@ package adminmonitor
import ( import (
"context" "context"
"log" "log"
"sync"
"time" "time"
portainer "github.com/portainer/portainer/api" portainer "github.com/portainer/portainer/api"
@ -16,6 +17,7 @@ type Monitor struct {
datastore dataservices.DataStore datastore dataservices.DataStore
shutdownCtx context.Context shutdownCtx context.Context
cancellationFunc context.CancelFunc cancellationFunc context.CancelFunc
mu sync.Mutex
} }
// New creates a monitor that when started will wait for the timeout duration and then shutdown the application unless it has been initialized. // New creates a monitor that when started will wait for the timeout duration and then shutdown the application unless it has been initialized.
@ -29,6 +31,13 @@ func New(timeout time.Duration, datastore dataservices.DataStore, shutdownCtx co
// Starts starts the monitor. Active monitor could be stopped or shuttted down by cancelling the shutdown context. // Starts starts the monitor. Active monitor could be stopped or shuttted down by cancelling the shutdown context.
func (m *Monitor) Start() { func (m *Monitor) Start() {
m.mu.Lock()
defer m.mu.Unlock()
if m.cancellationFunc != nil {
return
}
cancellationCtx, cancellationFunc := context.WithCancel(context.Background()) cancellationCtx, cancellationFunc := context.WithCancel(context.Background())
m.cancellationFunc = cancellationFunc m.cancellationFunc = cancellationFunc
@ -53,6 +62,9 @@ func (m *Monitor) Start() {
// Stop stops monitor. Safe to call even if monitor wasn't started. // Stop stops monitor. Safe to call even if monitor wasn't started.
func (m *Monitor) Stop() { func (m *Monitor) Stop() {
m.mu.Lock()
defer m.mu.Unlock()
if m.cancellationFunc == nil { if m.cancellationFunc == nil {
return return
} }

@ -21,6 +21,18 @@ func Test_stopCouldBeCalledMultipleTimes(t *testing.T) {
monitor.Stop() monitor.Stop()
} }
func Test_startOrStopCouldBeCalledMultipleTimesConcurrently(t *testing.T) {
monitor := New(1*time.Minute, nil, context.Background())
go monitor.Start()
monitor.Start()
go monitor.Stop()
monitor.Stop()
time.Sleep(2 * time.Second)
}
func Test_canStopStartedMonitor(t *testing.T) { func Test_canStopStartedMonitor(t *testing.T) {
monitor := New(1*time.Minute, nil, context.Background()) monitor := New(1*time.Minute, nil, context.Background())
monitor.Start() monitor.Start()

Loading…
Cancel
Save