summaryrefslogtreecommitdiff
path: root/internal
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-04-03 08:06:43 +0300
committerPaul Buetow <paul@buetow.org>2026-04-03 08:06:43 +0300
commit170a4a9d46a32bcb28c04f6ff6bb1a48284ec424 (patch)
tree2befb9d05cb857327efd0ba65bf06ac52cff8b11 /internal
parentf4bc35c0a24766c8e9a155cbad5ffdaf088ec458 (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.go13
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