fix(update): re-check every launch when the cache says up-to-date
CheckForUpdate used to trust any cache entry less than 12h old whose CurrentAt matched the running binary. Problem: if a user installs v0.0.72 at 16:05 (cache: up-to-date) and a v0.0.73 release ships at 18:27, relaunching zot at 18:29 hits the fresh cache and never calls the github api \u2014 the update banner stays hidden until either 12h pass or the binary is rebuilt. Noticed in the wild: v0.0.73 latest, zot 0.0.72 running, no banner. Refined logic: only short-circuit on a cached entry when it already reports Available=true. If the cache says "up to date" we let the flow fall through to fetchLatestRelease and reconcile. The api call is a single ~4s timeout request; cheap enough to do on every up-to-date launch, and the common "cache already shows available" path still skips the network entirely. Also: manually cleared /Users/pat/Library/Application Support/zot/update-check.json on my local box so the next launch sees the new v0.0.73 release without waiting; that's user state, not something to commit.
- commit
- 916a6f71d10089261a261af091dc84ad98618c2c
- author
- patriceckhart · · 2026-04-20 16:31 UTC
- parent
- 13b8947
- signature
- unsigned
- refs
- tag: v0.0.74
1 file · +13 -1
M internal/agent/update.go +13 -1
| @@ -62,8 +62,20 @@ func CheckForUpdate(ctx context.Context, zotHome, currentVersion string) UpdateI | |||
| 62 | 62 | cachePath := filepath.Join(zotHome, updateCheckFile) | |
| 63 | 63 | if c, ok := readUpdateCache(cachePath); ok { | |
| 64 | 64 | // Cache is fresh and tracks the same binary version. | |
| 65 | + | // Additional guard: only trust the cache when it already | |
| 66 | + | // reports an available update. If the cache says "up to | |
| 67 | + | // date" (Latest <= Current) we re-check anyway so a | |
| 68 | + | // release published after the last launch is picked up | |
| 69 | + | // without waiting out the full TTL. The API call is a | |
| 70 | + | // single 4s request; cheap to do on every up-to-date | |
| 71 | + | // launch, and skips entirely for the common "installed a | |
| 72 | + | // new version, cache reports update available" path. | |
| 65 | 73 | if time.Since(c.CheckedAt) < updateCheckTTL && c.CurrentAt == currentVersion { | |
| 66 | - | return buildInfo(currentVersion, c.Latest, c.URL) | |
| 74 | + | info := buildInfo(currentVersion, c.Latest, c.URL) | |
| 75 | + | if info.Available { | |
| 76 | + | return info | |
| 77 | + | } | |
| 78 | + | // fall through to re-check | |
| 67 | 79 | } | |
| 68 | 80 | } | |
| 69 | 81 | ||
| @@ -62,8 +62,20 @@ func CheckForUpdate(ctx context.Context, zotHome, currentVersion string) UpdateI | |||||
| 62 | cachePath := filepath.Join(zotHome, updateCheckFile) | 62 | cachePath := filepath.Join(zotHome, updateCheckFile) | ||
| 63 | if c, ok := readUpdateCache(cachePath); ok { | 63 | if c, ok := readUpdateCache(cachePath); ok { | ||
| 64 | // Cache is fresh and tracks the same binary version. | 64 | // Cache is fresh and tracks the same binary version. | ||
| 65 | + | // Additional guard: only trust the cache when it already | |||
| 66 | + | // reports an available update. If the cache says "up to | |||
| 67 | + | // date" (Latest <= Current) we re-check anyway so a | |||
| 68 | + | // release published after the last launch is picked up | |||
| 69 | + | // without waiting out the full TTL. The API call is a | |||
| 70 | + | // single 4s request; cheap to do on every up-to-date | |||
| 71 | + | // launch, and skips entirely for the common "installed a | |||
| 72 | + | // new version, cache reports update available" path. | |||
| 65 | if time.Since(c.CheckedAt) < updateCheckTTL && c.CurrentAt == currentVersion { | 73 | if time.Since(c.CheckedAt) < updateCheckTTL && c.CurrentAt == currentVersion { | ||
| 66 | - | return buildInfo(currentVersion, c.Latest, c.URL) | 74 | + | info := buildInfo(currentVersion, c.Latest, c.URL) |
| 75 | + | if info.Available { | |||
| 76 | + | return info | |||
| 77 | + | } | |||
| 78 | + | // fall through to re-check | |||
| 67 | } | 79 | } | ||
| 68 | } | 80 | } | ||
| 69 | 81 | ||||