Repository navigation
perf(plugin): add timeout, offline fallback, and pinned caching for remote plugins - #3029
Merged
Merged
Conversation
…emote plugins Implements item 11 of specs/perf-improvements.md. - GitHub plugin files are fetched with a shared http.Client with a 15s timeout instead of a bare client with no timeout. - When a cached GitHub or git plugin file has expired and the refetch fails, the expired copy is used and a slog.Warn is logged. If nothing is cached, the error is returned as before. - Content fetched at a full 40-character commit hash (git `?rev=` or GitHub path/`?rev=`) is cached indefinitely and ignores DEVBOX_X_GITHUB_PLUGIN_CACHE_TTL. Branches, tags, and short hashes still expire after 24h. - Git plugins clone each repo/ref/rev once per process and read every file from that clone, instead of cloning once per file. A failed clone is remembered for the rest of the process. boxcli.Execute deletes the clones on exit. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Collaborator
Author
|
@claude ptal |
|
Claude finished @mikeland73's task in 29s —— View job Review of #3029I read the non-test diff ( What looks right
Minor points, none blocking
Everything else in "Not done" is a reasonable scope cut, including the missing |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Implements item 11 of
specs/perf-improvements.md. Remote (GitHub and git) plugins are cached on disk for 24h. When that cache expired, devbox made a blocking network call with no timeout and failed outright if the call failed. Git plugins pinned to a commit also did one full clone per file.Timeout
githubHTTPClientthat has a 15s timeout. Before, it was&http.Client{}with no timeout. There was no shared client or timeout constant to reuse. Other call sites use anything from 3s (nixpkgs check) to 10min (launcher download).Offline fallback
getOrFetchhelper ininternal/plugin/cache.go, used by both GitHub and git plugins in place offilecache.GetOrSet. If the cached entry has expired and the fetch fails, it returns the expired copy and logs aslog.Warn(only shown withDEVBOX_DEBUG=1, like the rest of the plugin logging). If nothing is cached, the fetch error is returned as before.filecachedidn't need to change:Getalready returns the decoded value together withfilecache.Expired.Commit-pinned content is cached indefinitely
Revis a full 40-character hex commit hash, files are cached with a ~100 year TTL andDEVBOX_X_GITHUB_PLUGIN_CACHE_TTLis ignored. Branches, tags, short hashes, and no ref still use 24h (or the env var).?rev=) and GitHub plugins (github:owner/repo/<sha>or?rev=). For GitHub, the URL already uses the rev (raw.githubusercontent.com/owner/repo/<sha>/...), so the content can't change.One clone per repo/ref
FileContentcall that missed the cache did a full clone (plugin.json, then one percreate_filesentry). Plugins in the same repo with differentdirs share a clone. Clone args,GIT_SSH_COMMANDhandling, and checkout ofrevare unchanged.boxcli.Executedefersplugin.RemoveGitClones()to delete them. Before, each clone was deleted right after reading the one file.Testing
internal/plugin/cache_test.go. Caches point at a temp dir viafilecache.WithCacheDir. git clones are stubbed and GitHub is anhttptestserver, so nothing uses the network:getOrFetch: fresh hit doesn't fetch, expired entry is refreshed, expired entry is used when the fetch fails, error when nothing is cached.remoteCacheTTL: full hashes (lower and upper case) are pinned. Short hashes, branches, and empty are not. The env var only applies to unpinned refs.dirs in the same repo/ref, and a second clone for another ref. Commit-pinned content doesn't expire with a 1ns TTL. Branch and short-hash refs do. Stale fallback when the clone fails. Error when nothing is cached, with only one clone attempt.TestGitPluginFileContentCacheRespectsEnvVarexpected an error after expiry with the repo deleted. It's nowTestGitPluginFileContentExpiredCloneFailsand expects the stale content, using a realfile://clone.go test -race ./internal/plugin/ ./internal/boxcli/andgo test ./internal/...pass.go tool golangci-lint run ./internal/plugin/... ./internal/boxcli/: 0 issues. Thegolangci-linton PATH is built with go1.24 and refuses to load this go1.27 module, so I used the repo's pinnedgo toolversion, same asdevbox run lint.Not done
git clonestill has no timeout.revclone is still a full clone followed bygit checkout. A shallow fetch of a single commit would be faster, but not every git server allows fetching an arbitrary SHA.🤖 Generated with Claude Code