Skip to content

TUI sync goroutine can leak when user navigates away mid-sync #24

Description

@detour1999

Follow-up from PR #22 adversarial review round 2 (finding #26).

Problem

`internal/tui/syncing.go` spawns a goroutine that emits progress via a buffered channel (buffer 100) with a blocking callback. If the user hits `q` in the syncing view, `internal/tui/app.go`'s handler calls `popView()` — NOT `tea.Quit` — so the Bubble Tea program stops calling `SyncingModel.Update`. The buffered channels fill, the goroutine blocks on send, and it holds the SQLite writer connection.

Failure scenario

  1. User starts `--full` sync in the TUI
  2. Hits `q` to browse existing data while sync continues
  3. Sync goroutine emits > 100 progress messages, blocks on send
  4. Writer connection held indefinitely, no further DB writes possible
  5. User later hits `q` at dashboard → `tea.Quit` → `defer database.Close()` fires while the sync goroutine is mid-transaction. Commit races with Close.

Data-corruption-adjacent (worst case: dropped transaction, weird state on next open).

Fix

Wire a context through the syncer so `popView()` cancels the sync goroutine cleanly. Options:

  1. Add `context.Context` to `sync.Syncer.Run`, thread through all the DB writes
  2. Add a `syncer.Cancel()` method that closes an internal quit channel and gracefully returns from Run

Discovered by

Reviewer #5 in the round-2 adversarial code review of PR #22 (2026-08).

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions