Stop stops the notifier and waits until it has stopped.
(ctx context.Context)
| 357 | |
| 358 | // Stop stops the notifier and waits until it has stopped. |
| 359 | func (m *Manager) Stop(ctx context.Context) error { |
| 360 | m.mu.Lock() |
| 361 | defer m.mu.Unlock() |
| 362 | |
| 363 | if m.closed { |
| 364 | return nil |
| 365 | } |
| 366 | m.closed = true |
| 367 | |
| 368 | m.log.Debug(context.Background(), "graceful stop requested") |
| 369 | |
| 370 | // If the notifier hasn't been started, we don't need to wait for anything. |
| 371 | // This is only really during testing when we want to enqueue messages only but not deliver them. |
| 372 | if m.notifier != nil { |
| 373 | m.notifier.stop() |
| 374 | } |
| 375 | |
| 376 | // Signal the stop channel to cause loop to exit. |
| 377 | close(m.stop) |
| 378 | |
| 379 | if m.notifier == nil { |
| 380 | return nil |
| 381 | } |
| 382 | |
| 383 | m.mu.Unlock() // Unlock to avoid blocking loop. |
| 384 | defer m.mu.Lock() // Re-lock the mutex due to earlier defer. |
| 385 | |
| 386 | // Wait for the manager loop to exit or the context to be canceled, whichever comes first. |
| 387 | select { |
| 388 | case <-ctx.Done(): |
| 389 | var errStr string |
| 390 | if ctx.Err() != nil { |
| 391 | errStr = ctx.Err().Error() |
| 392 | } |
| 393 | // For some reason, slog.Error returns {} for a context error. |
| 394 | m.log.Error(context.Background(), "graceful stop failed", slog.F("err", errStr)) |
| 395 | return ctx.Err() |
| 396 | case <-m.done: |
| 397 | m.log.Debug(context.Background(), "gracefully stopped") |
| 398 | return nil |
| 399 | } |
| 400 | } |
| 401 | |
| 402 | type dispatchResult struct { |
| 403 | notifier uuid.UUID |