Skip to content

Fix race condition in concurrent cache writes at startup #92

@joshuacrass

Description

@joshuacrass

Problem:
saveIssuesToCacheCmd and savePRsToCacheCmd in app.go both fire concurrently at startup via tea.Batch. Each goroutine follows a load → mutate → write-back pattern on the same cache file. Two goroutines doing this simultaneously have a TOCTOU window: both read the same stale cache, then one goroutine's write silently overwrites the other's, causing either issues or PRs to be lost from the cache.

func saveIssuesToCacheCmd(issues []github.Issue) tea.Cmd {
    return func() tea.Msg {
        c := loadCache()    // both goroutines read here
        c.SetIssues(issues)
        _ = saveCache(c)    // one overwrites the other
        return nil
    }
}

Solution:
Add a sync.Mutex at the package level (or on AppCache) guarding the cache file write. Alternatively, redesign so each save function only writes its own section rather than load-modify-save the whole file.

Acceptance Criteria:

  • Concurrent calls to saveIssuesToCacheCmd and savePRsToCacheCmd cannot overwrite each other's data
  • Cache file is always valid JSON after concurrent writes
  • No regression in cache read/write behaviour
  • go test -race ./... passes

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions