Skip to content

Commit 9f60b66

Browse files
committed
Cancel goroutine immediately on stop
Signed-off-by: Danny Kopping <danny@coder.com>
1 parent ff73789 commit 9f60b66

File tree

2 files changed

+12
-14
lines changed

2 files changed

+12
-14
lines changed

coderd/database/pubsub/latency.go

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package pubsub
33
import (
44
"bytes"
55
"context"
6+
"errors"
67
"fmt"
78
"sync/atomic"
89
"time"
@@ -23,8 +24,7 @@ type LatencyMeasurer struct {
2324
// background measurement members
2425
collections atomic.Int64
2526
last atomic.Value
26-
asyncTick *time.Ticker
27-
stop chan struct{}
27+
asyncCancel context.CancelCauseFunc
2828
}
2929

3030
type LatencyMeasurement struct {
@@ -39,7 +39,6 @@ func NewLatencyMeasurer(logger slog.Logger) *LatencyMeasurer {
3939
return &LatencyMeasurer{
4040
channel: uuid.New(),
4141
logger: logger,
42-
stop: make(chan struct{}, 1),
4342
}
4443
}
4544

@@ -86,8 +85,11 @@ func (lm *LatencyMeasurer) Measure(ctx context.Context, p Pubsub) LatencyMeasure
8685
// MeasureAsync runs latency measurements asynchronously on a given interval.
8786
// This function is expected to be run in a goroutine and will exit when the context is canceled.
8887
func (lm *LatencyMeasurer) MeasureAsync(ctx context.Context, p Pubsub, interval time.Duration) {
89-
lm.asyncTick = time.NewTicker(interval)
90-
defer lm.asyncTick.Stop()
88+
tick := time.NewTicker(interval)
89+
defer tick.Stop()
90+
91+
ctx, cancel := context.WithCancelCause(ctx)
92+
lm.asyncCancel = cancel
9193

9294
for {
9395
// run immediately on first call, then sleep a tick before each invocation
@@ -101,14 +103,12 @@ func (lm *LatencyMeasurer) MeasureAsync(ctx context.Context, p Pubsub, interval
101103
lm.last.Store(&measure)
102104

103105
select {
104-
case <-lm.asyncTick.C:
106+
case <-tick.C:
105107
continue
106108

107109
// bail out if signaled
108-
case <-lm.stop:
109-
return
110110
case <-ctx.Done():
111-
lm.logger.Debug(ctx, "async measurement context canceled", slog.Error(ctx.Err()))
111+
lm.logger.Debug(ctx, "async measurement cancelled", slog.Error(ctx.Err()))
112112
return
113113
}
114114
}
@@ -130,11 +130,9 @@ func (lm *LatencyMeasurer) MeasurementCount() int64 {
130130

131131
// Stop stops any background measurements.
132132
func (lm *LatencyMeasurer) Stop() {
133-
if lm.asyncTick == nil {
134-
return
133+
if lm.asyncCancel != nil {
134+
lm.asyncCancel(errors.New("stopped"))
135135
}
136-
lm.asyncTick.Stop()
137-
lm.stop <- struct{}{}
138136
}
139137

140138
func (lm *LatencyMeasurer) latencyChannelName() string {

coderd/database/pubsub/pubsub_linux_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -342,7 +342,7 @@ func TestMeasureLatency(t *testing.T) {
342342
ps, done := newPubsub()
343343
defer done()
344344

345-
ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(-time.Minute))
345+
ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(-time.Hour))
346346
defer cancel()
347347

348348
l := pubsub.NewLatencyMeasurer(logger).Measure(ctx, ps)

0 commit comments

Comments
 (0)