diff options
| author | Paul Buetow <paul@buetow.org> | 2026-04-03 08:06:43 +0300 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2026-04-03 08:06:43 +0300 |
| commit | 170a4a9d46a32bcb28c04f6ff6bb1a48284ec424 (patch) | |
| tree | 2befb9d05cb857327efd0ba65bf06ac52cff8b11 /internal | |
| parent | f4bc35c0a24766c8e9a155cbad5ffdaf088ec458 (diff) | |
task 00a: track background goroutines in WaitGroup and respect ctx.Done()
- startFileCheckTicker: add wg.Add(1)/wg.Done() so the app shutdown handler
waits for the ticker goroutine to exit (it already uses ctx.Done() to stop).
- post-delete cleanup goroutine: add wg.Add(1)/wg.Done() and a ctx.Done()
case so a shutdown during the 5-second polling window terminates cleanly
instead of leaking the goroutine.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Diffstat (limited to 'internal')
| -rw-r--r-- | internal/gui/navigation.go | 13 |
1 files changed, 12 insertions, 1 deletions
diff --git a/internal/gui/navigation.go b/internal/gui/navigation.go index c7e9264..f142f38 100644 --- a/internal/gui/navigation.go +++ b/internal/gui/navigation.go @@ -497,7 +497,11 @@ func (a *Application) startFileCheckTicker() { ticker := time.NewTicker(2 * time.Second) a.fileCheckTicker = ticker + // Track this goroutine in wg so the shutdown handler waits for it to exit. + // The ctx.Done() case ensures it exits promptly when the application closes. + a.wg.Add(1) go func() { + defer a.wg.Done() for { select { case <-ticker.C: @@ -800,17 +804,24 @@ func (a *Application) deleteCurrentWord() { // Start a cleanup goroutine to guard against directory recreation by racing // in-flight operations. Instead of a fixed sleep, poll hasActiveOperations // so the cleanup runs as soon as all operations for this word complete. + // Tracked in wg and respects ctx.Done() so the app can shut down cleanly. + a.wg.Add(1) go func() { + defer a.wg.Done() ticker := time.NewTicker(50 * time.Millisecond) defer ticker.Stop() timeout := time.NewTimer(5 * time.Second) defer timeout.Stop() - // Wait until all active operations for this word finish or timeout elapses. + // Wait until all active operations for this word finish, timeout elapses, + // or the application is shutting down. for { select { case <-timeout.C: // Proceed even if some operations are still pending. + case <-a.ctx.Done(): + // Application is shutting down — skip the cleanup. + return case <-ticker.C: if a.hasActiveOperations(deletedWord) { continue |
