Refresh HTTP cache on miss for exact-version restore (#3116)#7321
Refresh HTTP cache on miss for exact-version restore (#3116)#7321Saibamen wants to merge 1 commit into
Conversation
When a restore asks for an exact package version that the cached versions list does not contain, refresh the HTTP cache once and retry before declaring the package unresolved. This eliminates spurious NU1102 failures for the common publish-then-consume scenario without requiring users to discover --no-cache or clear the HTTP cache by hand. The refresh reuses the existing SourceCacheContext.WithRefreshCacheTrue plumbing, is bounded to at most one extra HTTP round-trip per cache key per restore, only fires on the failure path, and is opt-out via the NUGET_HTTP_CACHE_REFRESH_ON_MISS environment variable. Floating ranges already satisfied by the cached list are left alone to avoid amplifying traffic on common restores. Addresses NuGet/Home#3116.
|
|
||
| bool isStaleCacheMiss = match == null || IsCacheStaleForExactVersion(match, libraryRange); | ||
|
|
||
| if (isStaleCacheMiss |
There was a problem hiding this comment.
I don't know/think this is enough.
My interpretation is that this won't change anything right now.
ResolverUtility is called on per project basis and it may even be called multiple times during a single restore operation for different package versions/framework versions.
The SourceRepositoryDependencyProvider, which is the abstraction that handles querying the sources has a caching layer on its own that's not gonna be get overwritten by just requesting a cache refresh.
That component is shared across different projects for perf purposes, so that'd need to know it needs to do something different as well.
During a single restore operation, many projects may be restored, so if a refresh brings in new data, we'd need to ensure that we're not refreshing more than once during an operation. Not even for consistency purposes, but for perf as well
For example, A -> B -> C
If C has a graph where's a missing package version somewhere.
We wouldn't wasn't the restores for all 3 projects to request and get a refresh either. It's just unnecessary http calls.
Refresh anytime a version is missed is probably too much.
Refreshing once per restore operation when a version is missed would be great, but the perfect one would be the one the cache wouldn't be refreshed if the cache was generated during the current operation already.
Summary
Fixes the long-standing publish-then-consume failure tracked in NuGet/Home#3116. When a restore asks for an exact package version that the cached versions list does not contain, NuGet now refreshes the HTTP cache once and retries before declaring the package unresolved. This eliminates spurious
NU1102failures without users having to discover--no-cache,RestoreNoCache, ordotnet nuget locals http-cache --clear.The change extends the existing 2-attempt retry loop in
ResolverUtility.FindLibraryEntryAsyncand reusesSourceCacheContext.WithRefreshCacheTrue(), which already plumbs through to the in-memory caches inRemoteV3FindPackageByIdResource/HttpFileSystemBasedFindPackageByIdResourceand forcesMaxAge=0on the on-disk HTTP cache.Fixes NuGet/Home#3116
Behavior
Refresh fires only when all are true:
nullorLibraryType.Unresolvedafter the first pass.(libraryRange, framework)key in this restore.NUGET_HTTP_CACHE_REFRESH_ON_MISSis not set tofalse/0.Bounded to one extra HTTP round-trip per cache key per restore, only on the failure path. Floating ranges already satisfied by the cache are intentionally left alone.
Design proposal
Companion design proposal: NuGet/Home#14872 (
accepted/2026/refresh-http-cache-on-miss.md). It covers the broader rationale, alternatives considered (not caching 404s, shortening TTL, always going to origin, honouring serverCache-Control), prior art (Cargo, npm, pip), and follow-ups deferred from this PR (nuget.configknobhttp_cache_refresh_on_miss, MSBuild propertyRestoreHttpCacheRefreshOnMiss,HttpCacheRefreshOnMissCounttelemetry, application to the MSBuild SDK resolver).Test plan
FindPackageTests:FindPackage_WhenExactVersionNotInCachedList_RefreshesHttpCacheAndResolves- cache miss for exact version triggers exactly one refresh and resolves.FindPackage_WhenExactVersionStillNotFoundAfterRefresh_ReturnsUnresolved- version genuinely absent results in exactly two find calls, result isUnresolved.FindPackage_WhenFloatingRangeIsSatisfiedFromStaleCache_DoesNotRefresh- floating ranges satisfied by cache do not trigger a refresh.FindPackageTestspass on net10.0.NuGet.DependencyResolver.Core.csprojbuilds clean for bothnet472andnet8.0.Notes / follow-ups
NUGET_HTTP_CACHE_REFRESH_ON_MISS). Thenuget.confighttp_cache_refresh_on_misskey andRestoreHttpCacheRefreshOnMissMSBuild property described in the design proposal are deferred to a follow-up to keep this change small.Log_RefreshingHttpCacheOnMissin the normal localization flow.