Skip to content

Commit 533c6dc

Browse files
fix: remove error log when notification manager is already closed (#18264)
Closes coder/internal#677 Resolves flakes such as: ``` $ go test -race -run "TestRunStopRace" github.com/coder/coder/v2/coderd/notifications -count=10000 -parallel $(nproc) --- FAIL: TestRunStopRace (0.00s) t.go:106: 2025-06-06 02:44:39.348 [debu] notifications-manager: notification manager started t.go:106: 2025-06-06 02:44:39.348 [debu] notifications-manager: graceful stop requested t.go:106: 2025-06-06 02:44:39.348 [debu] notifications-manager: notification manager stopped t.go:115: 2025-06-06 02:44:39.348 [erro] notifications-manager: notification manager stopped with error ... error= manager already closed: github.com/coder/coder/v2/coderd/notifications.(*Manager).loop /home/coder/coder/coderd/notifications/manager.go:166 *** slogtest: log detected at level ERROR; TEST FAILURE *** --- FAIL: TestRunStopRace (0.00s) t.go:106: 2025-06-06 02:44:41.632 [debu] notifications-manager: notification manager started t.go:106: 2025-06-06 02:44:41.632 [debu] notifications-manager: graceful stop requested t.go:106: 2025-06-06 02:44:41.632 [debu] notifications-manager: notification manager stopped t.go:115: 2025-06-06 02:44:41.633 [erro] notifications-manager: notification manager stopped with error ... error= manager already closed: github.com/coder/coder/v2/coderd/notifications.(*Manager).loop /home/coder/coder/coderd/notifications/manager.go:166 *** slogtest: log detected at level ERROR; TEST FAILURE *** FAIL FAIL github.com/coder/coder/v2/coderd/notifications 6.847s FAIL ``` These error logs are caused as a result of the `Manager` `Run` start operation being asynchronous. In the flaking test case we immediately call `Stop` after `Run`. It's possible for `Stop` to be scheduled to completion before the goroutine spawned by `Run` calls `loop` and checks `closed`. If this happens, `loop` returns an error and produces the error log. We'll address this by replacing this specific error log with a warning log. ``` $ go test -run "TestRunStopRace" github.com/coder/coder/v2/coderd/notifications -count=10000 -parallel $(nproc) ok github.com/coder/coder/v2/coderd/notifications 1.294s $ go test -race github.com/coder/coder/v2/coderd/notifications -count=100 -parallel $(nproc) ok github.com/coder/coder/v2/coderd/notifications 26.525s ```
1 parent 7c2fb66 commit 533c6dc

File tree

1 file changed

+8
-2
lines changed

1 file changed

+8
-2
lines changed

coderd/notifications/manager.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,8 @@ func (m *Manager) WithHandlers(reg map[database.NotificationMethod]Handler) {
135135
m.handlers = reg
136136
}
137137

138+
var ErrManagerAlreadyClosed = xerrors.New("manager already closed")
139+
138140
// Run initiates the control loop in the background, which spawns a given number of notifier goroutines.
139141
// Manager requires system-level permissions to interact with the store.
140142
// Run is only intended to be run once.
@@ -146,7 +148,11 @@ func (m *Manager) Run(ctx context.Context) {
146148
go func() {
147149
err := m.loop(ctx)
148150
if err != nil {
149-
m.log.Error(ctx, "notification manager stopped with error", slog.Error(err))
151+
if xerrors.Is(err, ErrManagerAlreadyClosed) {
152+
m.log.Warn(ctx, "notification manager stopped with error", slog.Error(err))
153+
} else {
154+
m.log.Error(ctx, "notification manager stopped with error", slog.Error(err))
155+
}
150156
}
151157
}()
152158
})
@@ -163,7 +169,7 @@ func (m *Manager) loop(ctx context.Context) error {
163169
m.mu.Lock()
164170
if m.closed {
165171
m.mu.Unlock()
166-
return xerrors.New("manager already closed")
172+
return ErrManagerAlreadyClosed
167173
}
168174

169175
var eg errgroup.Group

0 commit comments

Comments
 (0)