Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ENG-9500] Implement save-cache and restore-cache functions #289

Open
wants to merge 4 commits into
base: main
Choose a base branch
from

Conversation

khamilowicz
Copy link
Contributor

@khamilowicz khamilowicz commented Nov 14, 2023

Why

ENG-9500

User should be able to save and restore files in their custom builds as steps.

This is part 1 of this feature. It provides two new custom build functions: eas/save-cache and eas/restore-cache.

build:
  name: Foobar
  steps:
    - eas/checkout
    - eas/restore-cache:
      inputs:
        key: cache-key
        paths: node_modules
    - eas/install_node_module
    - eas/save-cache:
        inputs:
          key: cache-key
          paths: node_modules

Future PR will allow passing lists of files to paths parameter and define dynamic cache-key.

How

This PR implements eas/reastore-cache and eas/save-cache functions and lays foundations for future PRs.
Cache type is enhanced with downloadUrls attribute which will store mappings between cache keys and signed urls with cached files. Field will be populated by launcher.
CacheManager now accepts two parameters: build context (which is either BuildStepContext or BuildContext<Job>) and Cache. Implementation of CacheManager using dynamic cache urls will be provided in future PRs. Until this happens, for compatibility, build context is using any type.

Test Plan

These changes are not meant to provide working functionality, but to provide foundation for new GCSCacheManager implementation.

Copy link

linear bot commented Nov 14, 2023

Copy link

codecov bot commented Nov 14, 2023

Codecov Report

Attention: Patch coverage is 90.72165% with 9 lines in your changes are missing coverage. Please review.

Project coverage is 91.43%. Comparing base (74d8c65) to head (db0ebe4).
Report is 2 commits behind head on main.

❗ Current head db0ebe4 differs from pull request most recent head fdb4f77. Consider uploading reports for the commit fdb4f77 to get more accurate results

Files Patch % Lines
packages/steps/src/cli/cli.ts 0.00% 3 Missing ⚠️
packages/steps/src/inputFunctions.ts 86.37% 3 Missing ⚠️
packages/steps/src/BuildStepInput.ts 93.11% 2 Missing ⚠️
packages/steps/src/utils/template.ts 96.43% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #289      +/-   ##
==========================================
+ Coverage   88.51%   91.43%   +2.92%     
==========================================
  Files          23       23              
  Lines        1114     1085      -29     
  Branches      247      229      -18     
==========================================
+ Hits          986      992       +6     
+ Misses        128       93      -35     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@khamilowicz khamilowicz changed the title Piotrekszeremeta/eng 9500 caching for custom builds [ENG-9500] Caching for custom builds Nov 20, 2023
@khamilowicz khamilowicz force-pushed the piotrekszeremeta/eng-9500-caching-for-custom-builds branch 11 times, most recently from 155ed7f to 569cd61 Compare November 21, 2023 12:04
@khamilowicz khamilowicz force-pushed the piotrekszeremeta/eng-9500-caching-for-custom-builds branch 5 times, most recently from 4c39620 to 9685659 Compare January 3, 2024 13:11
@khamilowicz khamilowicz changed the title [ENG-9500] Caching for custom builds [ENG-9500] Implement save-cache and restore-cache functions Jan 3, 2024
@khamilowicz khamilowicz force-pushed the piotrekszeremeta/eng-9500-caching-for-custom-builds branch from 9685659 to 9eb71f1 Compare January 3, 2024 14:20
Comment on lines 27 to 29
saveCache(ctx: any, cache?: Cache): Promise<boolean | void>;
// TOOD: Change any to CacheableContext
restoreCache(ctx: any, cache: Cache): Promise<boolean | void>;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When does it return boolean and when does it return void? Suggestion: make it either one or the other.

Why saveCache doesn't require the cache argument?

Copy link
Contributor Author

@khamilowicz khamilowicz Jan 30, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

void is here only to keep compatibility with GCSCacheManager in turtle (https://github.com/expo/turtle-v2/blob/9e6fd370c862869fec034d7e1be1074f7d3e3105/src/services/worker/src/CacheManager.ts#L18) and will be changed when changes to turtle land

Copy link
Contributor

@sjchmiela sjchmiela Jan 30, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My suggestion to make development of this feature easier will be to do as follows:

  • make all necessary changes in eas-build. They can break API. We shouldn't try to deploy turtle-v2 with new cache changes (bumped dependencies), but without your adjusting changes (making GCSCacheManager conform to new restoreCache.
  • submit a pull request with upgraded dependencies and updated turtle-v2 code.

This is the flow I used when developing generic artifacts:

This removes the complexity of trying to maintain two interfaces at the same time. What do you think, do you foresee any problems?

Suggestion also applies to other comments like #289 (comment).

saveCache(ctx: any, cache?: Cache): Promise<boolean | void>;
// TOOD: Change any to CacheableContext
restoreCache(ctx: any, cache: Cache): Promise<boolean | void>;
generateUrls?: boolean;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does this do? Is this like a feature-enabling flag?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it will tell new GCSCacheManager whether to use pregenerated upload/download urls or to generate new ones.

packages/steps/src/BuildStepContext.ts Outdated Show resolved Hide resolved
packages/eas-build-job/src/common.ts Outdated Show resolved Hide resolved
Comment on lines +4 to +5
disabled: boolean;
clear: boolean;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do these do?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unresolving discussion. It remains unclear what does disabled or clear mean in this context.

packages/steps/src/cacheUtils.ts Outdated Show resolved Hide resolved
@@ -0,0 +1,31 @@
import { bunyan } from '@expo/logger';

export interface Cache {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to have two Caches, one here and another one in eas-build-job?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is part of the transition process: in order to avoid circular dependencies Cache should be defined in steps, but to keep compatibility I kept it in both places. It will be consolidated after changes to turtle

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this still true after recent changes to Turtle? Why would we get a circular dependency if we used Cache from eas-build-job?

packages/build-tools/src/steps/functions/cache.ts Outdated Show resolved Hide resolved
@khamilowicz khamilowicz marked this pull request as ready for review January 30, 2024 13:32
@@ -56,6 +59,9 @@ export class CustomBuildContext implements ExternalBuildContextProvider {
this.runtimeApi = {
uploadArtifacts: (...args) => buildCtx['uploadArtifacts'](...args),
};
this.cacheManager = buildCtx.cacheManager;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could consider rolling cacheManager into runtimeApi for simplicity. Like, how many functions may we put into runtimeApi? I don't think the list will be too long.

@khamilowicz khamilowicz force-pushed the piotrekszeremeta/eng-9500-caching-for-custom-builds branch 2 times, most recently from 6615c81 to db0ebe4 Compare March 5, 2024 17:45
@khamilowicz
Copy link
Contributor Author

@sjchmiela

@khamilowicz khamilowicz force-pushed the piotrekszeremeta/eng-9500-caching-for-custom-builds branch 2 times, most recently from b119c69 to 9800877 Compare April 16, 2024 14:51
Copy link
Contributor

@sjchmiela sjchmiela left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very cool, some questions and suggestions!

],
outputProviders: [
BuildStepOutput.createProvider({
id: 'cache_key',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I think key should be sufficient, same for paths.

Or, we could not add it because however users are providing us key and paths, they should be able to use the same technique anywhere else? This is not a strong opinion.

return;
}

const job = stepsCtx.global.staticContext.job as BuildJob;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the function only makes sense for a BuildJob let's define argument to this function like

export function createResolveBuildConfigBuildFunction(
ctx: CustomBuildContext<BuildJob>
): BuildFunction {
so types require a BuildJob and we don't need to cast.

However, I think the bigger thing to update here is that I think this doesn't take into consideration updates to https://github.com/expo/turtle-v2/pull/1715, e.g. that cache download URLs are to be requested dynamically from the launcher?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

However, I think the bigger thing to update here is that I think this doesn't take into consideration updates to https://github.com/expo/turtle-v2/pull/1715, e.g. that cache download URLs are to be requested dynamically from the launcher?

What makes you think so?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • call to restoreCache depends on job.cache existence
  • restoreCache receives job.cache

I thought dynamic caches are completely separate from job.cache.

@@ -11,6 +11,7 @@ if [[ "$npm_lifecycle_event" == "prepack" ]]; then
echo 'Removing "dist_commonjs" and "dist_esm" folders...'
rm -rf dist_commonjs dist_esm
fi
rm -rf dist_commonjs dist_esm
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did you need to add this? Can we remove it or submit a different pull request explaining the reason for this addition?

packages/steps/package.json Outdated Show resolved Hide resolved
Comment on lines +4 to +5
disabled: boolean;
clear: boolean;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unresolving discussion. It remains unclear what does disabled or clear mean in this context.

packages/steps/src/__tests__/fixtures/build.yml Outdated Show resolved Hide resolved
packages/steps/src/BuildWorkflowValidator.ts Outdated Show resolved Hide resolved
packages/steps/src/BuildStepInput.ts Outdated Show resolved Hide resolved
@khamilowicz khamilowicz force-pushed the piotrekszeremeta/eng-9500-caching-for-custom-builds branch from 9800877 to a3dcacf Compare May 13, 2024 12:30
@khamilowicz khamilowicz force-pushed the piotrekszeremeta/eng-9500-caching-for-custom-builds branch from a3dcacf to fdb4f77 Compare May 13, 2024 12:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants