-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(npm): stale metadata cache issue (#6101)
**What's the problem this PR addresses?** We now keep the package metadata in cache. To avoid missing new packages being released we have a check so that we only accept the cached metadata if 1/ the request asks for a semver version (not a range), and 2/ the requested version is found inside the cached metadata. In theory this means that whenever a dependency asks for a version we didn't cache, we assume something new got published, and we refetch it. However, to prevent fetching the package metadata many times for many different versions or ranges, we also have an in-memory metadata cache where we store the cached metadata once we extracted them from either the disk or the network. This may lead to memory cache corruption issues when two versions from the same package are resolved if one exists in the cached metadata but the other doesn't. In that case, the first package will pass the check for "is this version inside the cached metadata", get stored in the in-memory cache, and be reused for further resolutions (even if those resolutions would have failed this check). This is because the disk cache and the memory cache are the same. Fixes #5989 **How did you fix it?** I separated the in-memory cache into two buckets: the disk cache, and the network cache. This ensures that the disk cache gets properly ignored when retrieving versions we don't know, rather than be mistakenly assumed to be what the network fetched. **Checklist** <!--- Don't worry if you miss something, chores are automatically tested. --> <!--- This checklist exists to help you remember doing the chores when you submit a PR. --> <!--- Put an `x` in all the boxes that apply. --> - [x] I have read the [Contributing Guide](https://yarnpkg.com/advanced/contributing). <!-- See https://yarnpkg.com/advanced/contributing#preparing-your-pr-to-be-released for more details. --> <!-- Check with `yarn version check` and fix with `yarn version check -i` --> - [x] I have set the packages that need to be released for my changes to be effective. <!-- The "Testing chores" workflow validates that your PR follows our guidelines. --> <!-- If it doesn't pass, click on it to see details as to what your PR might be missing. --> - [x] I will check that all automated PR checks pass before the PR gets reviewed.
- Loading branch information
Showing
3 changed files
with
202 additions
and
79 deletions.
There are no files selected for viewing
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
releases: | ||
"@yarnpkg/cli": patch | ||
"@yarnpkg/plugin-npm": patch | ||
|
||
declined: | ||
- "@yarnpkg/plugin-compat" | ||
- "@yarnpkg/plugin-constraints" | ||
- "@yarnpkg/plugin-dlx" | ||
- "@yarnpkg/plugin-essentials" | ||
- "@yarnpkg/plugin-init" | ||
- "@yarnpkg/plugin-interactive-tools" | ||
- "@yarnpkg/plugin-nm" | ||
- "@yarnpkg/plugin-npm-cli" | ||
- "@yarnpkg/plugin-pack" | ||
- "@yarnpkg/plugin-patch" | ||
- "@yarnpkg/plugin-pnp" | ||
- "@yarnpkg/plugin-pnpm" | ||
- "@yarnpkg/plugin-stage" | ||
- "@yarnpkg/plugin-typescript" | ||
- "@yarnpkg/plugin-version" | ||
- "@yarnpkg/plugin-workspace-tools" | ||
- "@yarnpkg/builder" | ||
- "@yarnpkg/core" | ||
- "@yarnpkg/doctor" |
59 changes: 59 additions & 0 deletions
59
packages/acceptance-tests/pkg-tests-specs/sources/features/resolutionCache.test.ts
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
import {Filename, ppath, xfs} from '@yarnpkg/fslib'; | ||
import {tests} from 'pkg-tests-core'; | ||
|
||
describe(`Features`, () => { | ||
describe(`Resolution cache`, () => { | ||
test( | ||
`it should use a cache metadata when resolving fixed versions`, | ||
makeTemporaryEnv({}, { | ||
enableGlobalCache: false, | ||
}, async ({path, run, source}) => { | ||
await run(`add`, `[email protected]`); | ||
|
||
await xfs.removePromise(ppath.join(path, Filename.lockfile)); | ||
|
||
// We now hide any version other than 1.0.0 from the registry. If the | ||
// install passes, it means that Yarn read the metadata from the cache rather | ||
// than the registry, as we wanted. | ||
|
||
await tests.setPackageWhitelist(new Map([ | ||
[`no-deps`, new Set([`1.0.0`])], | ||
]), async () => { | ||
await run(`install`); | ||
}); | ||
}), | ||
); | ||
|
||
test( | ||
`it should properly separate the disk metadata cache from the network metadata cache`, | ||
makeTemporaryEnv({}, { | ||
enableGlobalCache: false, | ||
}, async ({path, run, source}) => { | ||
await tests.setPackageWhitelist(new Map([ | ||
[`no-deps`, new Set([`1.0.0`])], | ||
]), async () => { | ||
await run(`add`, `[email protected]`); | ||
}); | ||
|
||
await xfs.removePromise(ppath.join(path, Filename.lockfile)); | ||
|
||
// At this point, no-deps has been added into the metadata cache, but only | ||
// with the 1.0.0 version. The metadata cache isn't aware of other versions. | ||
|
||
// Now, we need a way to force the resolution cache to be used before resolving | ||
// a version that it isn't aware of. To that end, we create a package.json with | ||
// a dependency on one-fixed-dep@2, and we run 'yarn add [email protected]'. This | ||
// ensure that Yarn will run getCandidate on [email protected] first (because it's | ||
// required before adding it to the package.json), and [email protected] later. | ||
|
||
await xfs.writeFilePromise(ppath.join(path, Filename.manifest), JSON.stringify({ | ||
dependencies: { | ||
[`one-fixed-dep`]: `2.0.0`, | ||
}, | ||
})); | ||
|
||
await run(`add`, `[email protected]`); | ||
}), | ||
); | ||
}); | ||
}); |
This file contains 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