Skip to content

Commit 09a2b7c

Browse files
committed
fix(controller): race condition in handleSigterm() test
Fix a race condition between the signal handler setup and the signal send in the test for handleSigterm()
1 parent 4de8bd6 commit 09a2b7c

File tree

2 files changed

+21
-6
lines changed

2 files changed

+21
-6
lines changed

controller/execute.go

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ func Execute() {
100100
ctx, cancel := context.WithCancel(context.Background())
101101

102102
go serveMetrics(cfg.MetricsAddress)
103-
go handleSigterm(cancel)
103+
setupSigtermHandler(cancel)
104104

105105
endpointsSource, err := buildSource(ctx, cfg)
106106
if err != nil {
@@ -470,14 +470,23 @@ func createDomainFilter(cfg *externaldns.Config) *endpoint.DomainFilter {
470470

471471
// handleSigterm listens for a SIGTERM signal and triggers the provided cancel function
472472
// to gracefully terminate the application. It logs a message when the signal is received.
473-
func handleSigterm(cancel func()) {
473+
// The setupCh channel is used to signal when the signal handler is ready to receive signals.
474+
func handleSigterm(cancel func(), setupCh chan struct{}) {
474475
signals := make(chan os.Signal, 1)
475476
signal.Notify(signals, syscall.SIGTERM)
477+
close(setupCh)
476478
<-signals
477479
log.Info("Received SIGTERM. Terminating...")
478480
cancel()
479481
}
480482

483+
// setupSigtermHandler initializes the SIGTERM handler in a separate goroutine and waits for it to be ready.
484+
func setupSigtermHandler(cancel func()) {
485+
setupCh := make(chan struct{})
486+
go handleSigterm(cancel, setupCh)
487+
<-setupCh
488+
}
489+
481490
// serveMetrics starts an HTTP server that serves health and metrics endpoints.
482491
// The /healthz endpoint returns a 200 OK status to indicate the service is healthy.
483492
// The /metrics endpoint serves Prometheus metrics.

controller/execute_test.go

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ func TestCreateDomainFilter(t *testing.T) {
189189
}
190190
}
191191

192-
func TestHandleSigterm(t *testing.T) {
192+
func TestSetupSigterm(t *testing.T) {
193193
cancelCalled := make(chan bool, 1)
194194
cancel := func() {
195195
cancelCalled <- true
@@ -199,20 +199,26 @@ func TestHandleSigterm(t *testing.T) {
199199
log.SetOutput(&logOutput)
200200
defer log.SetOutput(os.Stderr)
201201

202-
go handleSigterm(cancel)
202+
setupSigtermHandler(cancel)
203203

204204
// Simulate sending a SIGTERM signal
205205
sigChan := make(chan os.Signal, 1)
206206
signal.Notify(sigChan, syscall.SIGTERM)
207207
err := syscall.Kill(syscall.Getpid(), syscall.SIGTERM)
208208
assert.NoError(t, err)
209209

210+
// Wait for the signal to be received
211+
select {
212+
case sig := <-sigChan:
213+
assert.Equal(t, syscall.SIGTERM, sig)
214+
case <-time.After(1 * time.Second):
215+
t.Fatal("signal was not recieved")
216+
}
217+
210218
// Wait for the cancel function to be called
211219
select {
212220
case <-cancelCalled:
213221
assert.Contains(t, logOutput.String(), "Received SIGTERM. Terminating...")
214-
case sig := <-sigChan:
215-
assert.Equal(t, syscall.SIGTERM, sig)
216222
case <-time.After(1 * time.Second):
217223
t.Fatal("cancel function was not called")
218224
}

0 commit comments

Comments
 (0)