Skip to content

fix(update): wait briefly for the background update check before exiting - #205

Open
pjcdawkins wants to merge 3 commits into
mainfrom
cli-199-wait-briefly-for-the-background-update-check-before-exiting
Open

pjcdawkins wants to merge 3 commits into
mainfrom
cli-199-wait-briefly-for-the-background-update-check-before-exiting

Conversation

@pjcdawkins

@pjcdawkins pjcdawkins commented Oct 8, 2026 •

Copy link
Copy Markdown
Contributor

The update check runs in a background goroutine. Short commands such as --version exited before it could save its result to state.json, so the check was lost.

  • Decide synchronously whether a check is due (internal.StartUpdateCheck), and only then start it in the background.
  • Before exiting, wait up to 1 second for a running check: after the command, in exitWithError, and after --version (the check now starts before --version is handled). The wait only happens when a check is due, which is at most once per check interval (1 hour by default).
  • Record LastChecked before the request starts, so a slow or blocked network costs the wait at most once per check interval.
  • Add a 5 second timeout to the GitHub request.
  • Drop the unused version comparison from the check; the notice compares versions when it reads the cached result.

Verified by running upsun --version in a PTY with an empty home: main writes no state, this branch records the latest version.

🤖 Generated with Claude Code

Short commands such as `--version` exited before the update check could
save its result to the state file, so the check was lost.

- Decide synchronously whether a check is due, and only then start it in
  the background (`internal.StartUpdateCheck`).
- Before exiting, wait up to 1 second for a running check: after the
  command, in `exitWithError`, and after `--version` (the check now
  starts before `--version` is handled).
- Add a 5 second timeout to the GitHub request.
- Drop the unused version comparison from the check; the notice compares
  versions when it reads the cached result.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@upsun-dispatch upsun-dispatch Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Warning

Changes suggested — 🟡 1 warning

🔍 Full review · 4 files reviewed

Verification
  • state.Update holds a package mutex while it reloads the file, so MarkNotified running alongside the new goroutine cannot drop each other's fields.
  • UpdateCheck.Wait handles a nil receiver, so waitForUpdateCheck is safe on completion paths, help paths and paths where no check was started.
  • The removed CheckForUpdate has no remaining callers in the Go code.
  • StartUpdateCheck keeps the GitHubRepo != "" gate (through shouldCheckForUpdate) that the old call got from its enclosing if block.

The new TestUpdateCheckWait covers only the nil, finish and timeout cases of Wait. No test covers StartUpdateCheck, the root-command wiring, or what happens when the GitHub request runs longer than the wait. The CI test/lint jobs (make test / make lint) cover these files only to that extent.

Review details
  • Commit: 7038fcf
  • Model: claude-opus-5-5

Review 1 of 10 for this pull request · View the full run

Comment thread internal/update.go
Previously LastChecked was saved only after the GitHub request returned.
On a network where the request takes longer than the 1 second wait, the
process exited first, so every run started a new check and waited the
full second. Saving the attempt first limits this to once per check
interval.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@upsun-dispatch upsun-dispatch Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Warning

Changes suggested — 🟡 1 warning

🔁 Incremental · 1 file reviewed

Verification
  • LastChecked is now written synchronously, before the goroutine starts, so a request that outlives the process no longer leaves the check due on the next run.
  • The background state.Update now sets only KnownLatestVersion, and only when the release lookup succeeds with a non-empty tag, so a failed lookup no longer touches the cached version.
  • state.Update reloads the state under a mutex, so the background write of KnownLatestVersion cannot drop the LastChecked or LastNotified written on the main goroutine.

No test in this increment covers the new ordering: nothing asserts that LastChecked is saved before the request, or that a failed request leaves KnownLatestVersion alone. The repository's Go test job (make test) runs only the existing state and notification tests.

Review details

Review 2 of 10 for this pull request · View the full run

Comment thread internal/update.go Outdated
@upsun-dispatch
upsun-dispatch Bot dismissed their stale review October 8, 2026 23:48

Superseded: the latest Upsun Dispatch review no longer requests changes.

If the state file is not writable, LastChecked could not be recorded, so
every run would start a new check and wait for it. The result could not
be cached either, so the check is skipped.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant