mirror of
https://github.com/facebook/react-native.git
synced 2024-11-21 22:10:14 +00:00
Only cache node_modules on main (#45544)
Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/45544 ## This diff now does 5 things: 1. removes the old way we used `actions/setup-node` to manage the cache itself. 2. it creates a new `update-node-modules-cache` workflow, which is the only job that will update the node modules cache 3. it create a `yarn-install-with-cache` action that should be used install of directly calling `yarn install --non-interactive`. This will load a cache against a hash of `package.json`. 4. updated the cache reaper to aggressively remove everything but the latest `npm-{{ hash('package.json') }}`. 5. removed a `cache-setup`, which couldn't be used (we're using artefacts now). ## Why are we doing this: The various `node-cache-` keys for platforms and on various branches accounts for a very large proportion of the cache (10-20%). We don't frequently change these dependencies, and even when we do running `yarn install` after loading the cache will resolve any issues. Limiting the cache to `main` and aggressively pruning older cache entries will clean up a lot of "small win" caching. Changelog: [Internal] Reviewed By: cortinico Differential Revision: D59917944 fbshipit-source-id: 4be6f1959e8fde642a4f208f7d19aceba2c3262f
This commit is contained in:
parent
d9263fbdbb
commit
4410899ec7
5
.github/actions/build-android/action.yml
vendored
5
.github/actions/build-android/action.yml
vendored
@ -12,9 +12,8 @@ runs:
|
||||
run: git config --global --add safe.directory '*'
|
||||
- name: Setup node.js
|
||||
uses: ./.github/actions/setup-node
|
||||
- name: Install dependencies
|
||||
shell: bash
|
||||
run: yarn install --non-interactive
|
||||
- name: Install node dependencies
|
||||
uses: ./.github/actions/yarn-install-with-cache
|
||||
- name: Set React Native Version
|
||||
shell: bash
|
||||
run: node ./scripts/releases/set-rn-artifacts-version.js --build-type ${{ inputs.release-type }}
|
||||
|
@ -47,8 +47,7 @@ runs:
|
||||
fi
|
||||
- name: Yarn- Install Dependencies
|
||||
if: ${{ steps.check_if_apple_artifacts_are_there.outputs.ARTIFACTS_EXIST != 'true' }}
|
||||
shell: bash
|
||||
run: yarn install --non-interactive
|
||||
uses: ./.github/actions/yarn-install-with-cache
|
||||
- name: Slice cache macosx
|
||||
if: ${{ steps.check_if_apple_artifacts_are_there.outputs.ARTIFACTS_EXIST != 'true' }}
|
||||
uses: actions/download-artifact@v4
|
||||
|
3
.github/actions/build-npm-package/action.yml
vendored
3
.github/actions/build-npm-package/action.yml
vendored
@ -103,8 +103,7 @@ runs:
|
||||
- name: Setup gradle
|
||||
uses: ./.github/actions/setup-gradle
|
||||
- name: Install dependencies
|
||||
shell: bash
|
||||
run: yarn install --non-interactive
|
||||
uses: ./.github/actions/yarn-install-with-cache
|
||||
- name: Build packages
|
||||
shell: bash
|
||||
run: yarn build
|
||||
|
88
.github/actions/cache-setup/action.yml
vendored
88
.github/actions/cache-setup/action.yml
vendored
@ -1,88 +0,0 @@
|
||||
name: cache-setup
|
||||
description: "Cache setup"
|
||||
inputs:
|
||||
hermes-version:
|
||||
description: "Hermes version"
|
||||
required: true
|
||||
react-native-version:
|
||||
description: "React Native version"
|
||||
required: true
|
||||
outputs:
|
||||
cache-hit-hermes-tarball-release:
|
||||
description: "Whether the hermes tarball release cache was hit"
|
||||
value: ${{ steps.cache_hermes_tarball_release.outputs.cache-hit }}
|
||||
cache-hit-hermes-tarball-debug:
|
||||
description: "Whether the hermes tarball debug cache was hit"
|
||||
value: ${{ steps.cache_hermes_tarball_debug.outputs.cache-hit }}
|
||||
cache-hit-macos-bin-release:
|
||||
description: "Whether the macos bin release cache was hit"
|
||||
value: ${{ steps.cache_macos_bin_release.outputs.cache-hit }}
|
||||
cache-hit-macos-bin-debug:
|
||||
description: "Whether the macos bin debug cache was hit"
|
||||
value: ${{ steps.cache_macos_bin_debug.outputs.cache-hit }}
|
||||
cache-hit-dsym-release:
|
||||
description: "Whether the dsym release cache was hit"
|
||||
value: ${{ steps.cache_dsym_release.outputs.cache-hit }}
|
||||
cache-hit-dsym-debug:
|
||||
description: "Whether the dsym debug cache was hit"
|
||||
value: ${{ steps.cache_dsym_debug.outputs.cache-hit }}
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Cache hermes tarball release
|
||||
id: cache_hermes_tarball_release
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: /tmp/hermes/hermes-runtime-darwin/hermes-ios-Release.tar.gz
|
||||
key: v4-hermes-tarball-release-${{ inputs.hermes-version }}-${{ inputs.react-native-version }}-${{ hashfiles('packages/react-native/sdks/hermes-engine/utils/build-apple-framework.sh') }}
|
||||
enableCrossOsArchive: true
|
||||
- name: Cache hermes tarball debug
|
||||
id: cache_hermes_tarball_debug
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: /tmp/hermes/hermes-runtime-darwin/hermes-ios-Debug.tar.gz
|
||||
key: v4-hermes-tarball-debug-${{ inputs.hermes-version }}-${{ inputs.react-native-version }}-${{ hashfiles('packages/react-native/sdks/hermes-engine/utils/build-apple-framework.sh') }}
|
||||
enableCrossOsArchive: true
|
||||
- name: Cache macos bin release
|
||||
id: cache_macos_bin_release
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: /tmp/hermes/osx-bin/Release
|
||||
key: v2-hermes-release-macosx-${{ inputs.hermes-version }}-${{ inputs.react-native-version }}
|
||||
enableCrossOsArchive: true
|
||||
- name: Cache macos bin debug
|
||||
id: cache_macos_bin_debug
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: /tmp/hermes/osx-bin/Debug
|
||||
key: v2-hermes-debug-macosx-${{ inputs.hermes-version }}-${{ inputs.react-native-version }}
|
||||
enableCrossOsArchive: true
|
||||
- name: Cache dsym release
|
||||
id: cache_dsym_release
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: /tmp/hermes/dSYM/Release
|
||||
key: v2-hermes-release-dsym-${{ inputs.hermes-version }}-${{ inputs.react-native-version }}
|
||||
enableCrossOsArchive: true
|
||||
- name: Cache dsym debug
|
||||
id: cache_dsym_debug
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: /tmp/hermes/dSYM/Debug
|
||||
key: v2-hermes-debug-dsym-${{ inputs.hermes-version }}-${{ inputs.react-native-version }}
|
||||
enableCrossOsArchive: true
|
||||
- name: HermesC Apple
|
||||
id: hermesc_apple
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: /tmp/hermes/hermesc-apple
|
||||
key: v2-hermesc-apple-${{ inputs.hermes-version }}-${{ inputs.react-native-version }}
|
||||
enableCrossOsArchive: true
|
||||
- name: Cache hermes workspace
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
/tmp/hermes/download/
|
||||
/tmp/hermes/hermes/
|
||||
key: v1-hermes-${{ inputs.hermes-version }}
|
||||
enableCrossOsArchive: true
|
3
.github/actions/create-release/action.yml
vendored
3
.github/actions/create-release/action.yml
vendored
@ -15,8 +15,7 @@ runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Yarn install
|
||||
shell: bash
|
||||
run: yarn install --non-interactive
|
||||
uses: ./.github/actions/yarn-install-with-cache
|
||||
- name: Configure Git
|
||||
shell: bash
|
||||
run: |
|
||||
|
@ -69,8 +69,7 @@ runs:
|
||||
|
||||
- name: Yarn- Install Dependencies
|
||||
if: ${{ steps.meaningful-cache.outputs.HERMES_CACHED != 'true' }}
|
||||
shell: bash
|
||||
run: yarn install --non-interactive
|
||||
uses: ./.github/actions/yarn-install-with-cache
|
||||
|
||||
- name: Download Hermes tarball
|
||||
if: ${{ steps.meaningful-cache.outputs.HERMES_CACHED != 'true' }}
|
||||
|
5
.github/actions/setup-node/action.yml
vendored
5
.github/actions/setup-node/action.yml
vendored
@ -5,10 +5,6 @@ inputs:
|
||||
description: 'The node.js version to use'
|
||||
required: false
|
||||
default: '18'
|
||||
cache:
|
||||
description: 'The package manager to use for caching dependencies'
|
||||
required: false
|
||||
default: 'yarn'
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
@ -16,4 +12,3 @@ runs:
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ inputs.node-version }}
|
||||
cache: ${{ inputs.cache }}
|
||||
|
@ -41,8 +41,7 @@ runs:
|
||||
shell: bash
|
||||
run: ls -lR "$HERMES_WS_DIR"
|
||||
- name: Run yarn
|
||||
shell: bash
|
||||
run: yarn install --non-interactive
|
||||
uses: ./.github/actions/yarn-install-with-cache
|
||||
- name: Setup ruby
|
||||
uses: ruby/setup-ruby@v1.170.0
|
||||
with:
|
||||
|
3
.github/actions/test-ios-rntester/action.yml
vendored
3
.github/actions/test-ios-rntester/action.yml
vendored
@ -37,8 +37,7 @@ runs:
|
||||
- name: Setup node.js
|
||||
uses: ./.github/actions/setup-node
|
||||
- name: Run yarn
|
||||
shell: bash
|
||||
run: yarn install --non-interactive
|
||||
uses: ./.github/actions/yarn-install-with-cache
|
||||
- name: Download Hermes
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
|
3
.github/actions/test-js/action.yml
vendored
3
.github/actions/test-js/action.yml
vendored
@ -13,8 +13,7 @@ runs:
|
||||
with:
|
||||
node-version: ${{ inputs.node-version }}
|
||||
- name: Yarn install
|
||||
shell: bash
|
||||
run: yarn install --non-interactive
|
||||
uses: ./.github/actions/yarn-install-with-cache
|
||||
- name: Run Tests - JavaScript Tests
|
||||
shell: bash
|
||||
run: node ./scripts/run-ci-javascript-tests.js --maxWorkers 2
|
||||
|
28
.github/actions/yarn-install-with-cache/action.yml
vendored
Normal file
28
.github/actions/yarn-install-with-cache/action.yml
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
name: yarn-install-with-cache
|
||||
inputs:
|
||||
update-cache:
|
||||
description: Update the cache, only do this if you are update-node-modules-cache.yml
|
||||
default: "false"
|
||||
description: Only update node_modules if on main
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Load node_modules from cache
|
||||
# Restore for all branches, but save for 'main'.
|
||||
uses: actions/cache/restore@v4
|
||||
with:
|
||||
path: node_modules/
|
||||
key: node-modules-${{ hashFiles('package.json') }}
|
||||
- name: Install dependencies
|
||||
shell: bash
|
||||
run: yarn install --non-interactive
|
||||
- name: Save node_modules to the cache
|
||||
if: github.ref == 'refs/heads/main' && inputs.update-cache == 'true'
|
||||
uses: actions/cache/save@v4
|
||||
with:
|
||||
path: node_modules/
|
||||
# We're assuming that variations on branches will slightly vary from main,
|
||||
# so it's always important to run yarn install --non-interactive after this
|
||||
# cache is restored.
|
||||
key: node-modules-v1-${{ hashFiles('package.json') }}
|
||||
enableCrossOsArchive: true
|
@ -17,7 +17,7 @@ jobs:
|
||||
- name: Setup node.js
|
||||
uses: ./.github/actions/setup-node
|
||||
- name: Run Yarn Install
|
||||
run: yarn install
|
||||
uses: ./.github/actions/yarn-install-with-cache
|
||||
- name: Build packages
|
||||
run: yarn build
|
||||
- name: Set NPM auth token
|
||||
|
5
.github/workflows/test-all.yml
vendored
5
.github/workflows/test-all.yml
vendored
@ -291,9 +291,8 @@ jobs:
|
||||
path: /tmp/maven-local
|
||||
- name: Setup gradle
|
||||
uses: ./.github/actions/setup-gradle
|
||||
- name: Run yarn
|
||||
shell: bash
|
||||
run: yarn install --non-interactive
|
||||
- name: Run yarn install
|
||||
uses: ./.github/actions/yarn-install-with-cache
|
||||
- name: Prepare the Helloworld application
|
||||
shell: bash
|
||||
run: node ./scripts/e2e/init-project-e2e.js --useHelloWorld --pathToLocalReactNative "$GITHUB_WORKSPACE/build/$(cat build/react-native-package-version)"
|
||||
|
16
.github/workflows/update-node-modules-cache.yml
vendored
Normal file
16
.github/workflows/update-node-modules-cache.yml
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
name: Update node modules cache
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
update_node_modules_cache:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Install yarn dependencies and update cache
|
||||
uses: ./.github/actions/yarn-install-with-cache
|
||||
with:
|
||||
update-cache: "true"
|
@ -8,6 +8,8 @@
|
||||
const {execSync} = require('node:child_process');
|
||||
|
||||
const CACHE_LIMIT = (10 * 1024 ** 3) * 0.9;
|
||||
// Doing this to capture node-modules- and the pre-existing node-cache-<platform>-yarn-<sha> entries
|
||||
const NODE_CACHE_KEY = 'node-';
|
||||
|
||||
function cleanData(rawStr) {
|
||||
const now = new Date();
|
||||
@ -15,8 +17,10 @@ function cleanData(rawStr) {
|
||||
return json
|
||||
.map(raw => ({
|
||||
...raw,
|
||||
createdAt: now - new Date(raw.createdAt),
|
||||
msSinceLastAccessed: now - new Date(raw.lastAccessedAt),
|
||||
}))
|
||||
// Order: oldest last access time first
|
||||
.sort((a, b) => b.msSinceLastAccessed - a.msSinceLastAccessed);
|
||||
}
|
||||
|
||||
@ -25,26 +29,51 @@ const hrs = ms => (ms / (1000 * 60 * 60)).toFixed(1) + 'hrs';
|
||||
|
||||
const dryRun = process.argv.indexOf('--dry') !== -1;
|
||||
|
||||
function cacheToString(entry) {
|
||||
return `[${hrs(entry.msSinceLastAccessed).padStart(7)}] ${mb(entry.sizeInBytes).padStart(7)} -> ${entry.key}`;
|
||||
}
|
||||
|
||||
function main() {
|
||||
const cacheUsage = cleanData(execSync(
|
||||
'gh cache list --sort last_accessed_at --json id,key,lastAccessedAt,sizeInBytes --limit 1000',
|
||||
'gh cache list --sort last_accessed_at --json id,key,createdAt,lastAccessedAt,sizeInBytes --limit 1000',
|
||||
'utf8'
|
||||
));
|
||||
|
||||
let total = 0;
|
||||
let remove = [];
|
||||
let cleaned = 0;
|
||||
|
||||
// Be aggressive with node cache entries. Ignore entries < 1MB and only keep most
|
||||
// recently created entry.
|
||||
const nodeCacheUsage = cacheUsage
|
||||
.filter(({key, sizeInBytes}) =>
|
||||
// I've observed some noisy entries, ignore anything that isn't > 1MB
|
||||
key.startsWith(NODE_CACHE_KEY) && sizeInBytes > 1024 * 1024
|
||||
)
|
||||
.sort((a, b) => b.createdAt - a.createdAt);
|
||||
// Leave the latest entry only
|
||||
const keeping = nodeCacheUsage.pop();
|
||||
|
||||
console.log('TASK: clean up old node_modules cache entries.', keeping ? `\nkeeping ${cacheToString(keeping)}` : ' Skipping, no cache entries.');
|
||||
for (const entry of nodeCacheUsage) {
|
||||
console.warn(`removing ${cacheToString(entry)}`);
|
||||
cleaned += entry.sizeInBytes;
|
||||
remove.push(entry.id);
|
||||
}
|
||||
|
||||
// Cleanup everything else
|
||||
console.log('TASK: clean up everything else that takes us over our threshold: ' + mb(CACHE_LIMIT));
|
||||
for (let i = cacheUsage.length - 1; i > 0; i--) {
|
||||
const {id, key, msSinceLastAccessed, sizeInBytes} = cacheUsage[i];
|
||||
total += sizeInBytes;
|
||||
const cache = cacheUsage[i];
|
||||
total += cache.sizeInBytes;
|
||||
|
||||
// Are we in the danger zone?
|
||||
if (total > CACHE_LIMIT) {
|
||||
console.warn(`[${hrs(msSinceLastAccessed).padStart(7)}] ${mb(sizeInBytes).padStart(7)} -> ${key}`);
|
||||
cleaned += sizeInBytes;
|
||||
remove.push(id);
|
||||
console.warn(cacheToString(cacheUsage[i]));
|
||||
cleaned += cache.sizeInBytes;
|
||||
remove.push(cache.id);
|
||||
} else {
|
||||
console.warn(`skip ${cacheUsage.length - i} ${mb(sizeInBytes)} ${hrs(msSinceLastAccessed)}`);
|
||||
console.warn(`skip ${cacheUsage.length - i} ${mb(cache.sizeInBytes)} ${hrs(cache.msSinceLastAccessed)}`);
|
||||
}
|
||||
}
|
||||
console.warn(`Identifed ${remove.length} cache keys for removal, reducing cache from ${mb(total)} -> ${mb(total - cleaned)}`);
|
||||
@ -52,9 +81,9 @@ function main() {
|
||||
const cleanup = remove.map(id => `gh cache delete ${id} --repo facebook/react-native`);
|
||||
for (const cmd of cleanup) {
|
||||
if (dryRun) {
|
||||
console.warn(`DRY: ${cmd}`);
|
||||
console.warn(`Skip: ${cmd}`);
|
||||
} else {
|
||||
console.warn(`${cmd} -> ${execSync(cmd, 'utf8').toString()}`);
|
||||
console.warn(`${cmd} 🪓 ${execSync(cmd, 'utf8').toString()}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user