-
Notifications
You must be signed in to change notification settings - Fork 3.9k
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
feat(codebuild): add support for local cache modes #2529
feat(codebuild): add support for local cache modes #2529
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the contribution�!
Please update README with some details on this feature and use-cases (copy & paste from AWS docs)
@@ -16,6 +16,12 @@ const CODEPIPELINE_TYPE = 'CODEPIPELINE'; | |||
const S3_BUCKET_ENV = 'SCRIPT_S3_BUCKET'; | |||
const S3_KEY_ENV = 'SCRIPT_S3_KEY'; | |||
|
|||
export enum ProjectCacheModes { | |||
LocalSourceCache = 'LOCAL_SOURCE_CACHE', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The prefix "Local" seems unnecessary
@@ -16,6 +16,12 @@ const CODEPIPELINE_TYPE = 'CODEPIPELINE'; | |||
const S3_BUCKET_ENV = 'SCRIPT_S3_BUCKET'; | |||
const S3_KEY_ENV = 'SCRIPT_S3_KEY'; | |||
|
|||
export enum ProjectCacheModes { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add docstrings
|
||
### Local Caching | ||
|
||
With local caching, the cache is stored on the codebuild instance itself. Three different cache modes are supported: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One thing that's not clear from this is what causes a reuse of an instance? When is the local cache being utilized.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any reason why this we shouldn't enable this by default?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This also isn't entirely clear to me to be honest. The only hint regarding this is that "After a build, AWS CodeBuild maintains the cache for some time in anticipation of another build." (https://aws.amazon.com/about-aws/whats-new/2019/02/aws-codebuild-now-supports-local-caching/). My documentation is largely copy/pasted from the official documentation where this also isn't clearly mentioned.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Kaixiang-AWS can you weigh in here? Thanks!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
CodeBuild cannot guarantee a reuse of instance. It's a best effort. Imagine you have a build ran and cached on an instance, and then you have 2 builds start at the same time. Only one of them will utilize the cache and the other one will have to run on a new instance which doesn't have cache in it.
Anyway, I think the problem here is we might miss a modeling opportunity if we do it this way. Defining a base cache class and extending it to S3 or local caching might be a more feasible and extensible way. If there are more cache types in the future, in this way we only need to add another class which extends base class and don't need to handle the complicated input validation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! Can we put this info into the README?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done! I also looked into the refactor that @Kaixiang-AWS mentioned. I'm currently not experienced enough with Typescript and/or the CDK to properly implement this. Can we for now merge this PR and create a new issue to refactor it? The feature would at least become available if we merge the PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like @Kaixiang-AWS's suggestion. It's a pattern we've been using we call "union-like classes" and it fits this API perfectly. I rather we spend a bit more time now than introduce a breaking change later.
Here's a sketch:
export interface BucketCacheOptions {
cacheDir?: string;
}
export enum LocalCacheMode {
Source = 'LOCAL_SOURCE_CACHE',
DockerLayer = 'LOCAL_DOCKER_LAYER_CACHE',
Custom = 'LOCAL_CUSTOM_CACHE',
}
export abstract class Cache {
public static none(): Cache {
return { _toCloudFormation: () => undefined };
}
public static bucket(bucket: s3.IBucket, options: BucketCacheOptions): Cache {
const cacheDir = options.cacheDir ? options.cacheDir : Aws.noValue;
return { _toCloudFormation: () => ({
type: 'S3',
location: Fn.join('/', [ bucket.bucketName, cacheDir ])})
};
}
public static local(...modes: LocalCacheMode[]): Cache {
return {
_toCloudFormation: () => ({
type: 'LOCAL',
modes
})
};
}
/** @internal */
public abstract _toCloudFormation(): codebuild.CfnProject.ProjectCacheProperty | undefined;
}
export interface CommonProjectProps {
/**
* @default Cache.none
*/
readonly cache?: Cache;
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good, I'll dive into it 👍
Just pushed an update. Small notes:
|
With S3 caching, the cache is stored in an S3 bucket which is available from multiple hosts. | ||
|
||
```typescript | ||
new codebuild.Project(stack, 'Project', { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Replace stack
with this
everywhere
|
||
With local caching, the cache is stored on the codebuild instance itself. CodeBuild cannot guarantee a reuse of instance. For example, when a build starts and caches files locally, if two subsequent builds start at the same time afterwards only one of those builds would get the cache. Three different cache modes are supported: | ||
|
||
* `LocalCacheMode.SourceCache` caches Git metadata for primary and secondary sources. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove the postfix Cache
from these enum members.
* Local cache modes to enable for the CodeBuild Project | ||
*/ | ||
export enum LocalCacheMode { | ||
SourceCache = 'LOCAL_SOURCE_CACHE', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
2 spaces please
/** | ||
* If and what strategy to use for build caching | ||
*/ | ||
export enum CacheType { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we need to export this ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know why it's needed really.
}), | ||
_bind: (project) => { | ||
if (project.role) { | ||
bucket.grantReadWrite(project.role); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Project
should implement IGrantable
and then you should be able to just do bucket.grantReadWrite(project)
.
* @param bucket the S3 bucket to use for caching | ||
* @param prefix the optional prefix to use to store the cache in the bucket | ||
*/ | ||
public static bucket(bucket: IBucket, prefix?: string): Cache { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry but please use the the Options
API because it is future-compatible. If we end up needing more options, we'll have to break this API. It's also more readable when it's used: Cache.bucket(myBucket, 'foo')
as oppose to Cache.bucket(myBucket, { prefix: 'foo' })
.
@@ -696,7 +686,7 @@ export class Project extends ProjectBase { | |||
environment: this.renderEnvironment(props.environment, environmentVariables), | |||
encryptionKey: props.encryptionKey && props.encryptionKey.keyArn, | |||
badgeEnabled: props.badge, | |||
cache, | |||
cache: props.cache && props.cache._toCloudFormation() || Cache.none()._toCloudFormation(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Style: call ._toCloudFormation
once, so usually we do this:
const cache = props.cache || Cache.none();
// ...
cache: cache._toCloudFormation();
f167746
to
c49fdc7
Compare
3d16852
to
153d4db
Compare
153d4db
to
f2fc1be
Compare
```typescript | ||
new codebuild.Project(this, 'Project', { | ||
source: new codebuild.CodePipelineSource(), | ||
cache: Cache.bucket(new Bucket(this, 'Bucket')) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It should be codebuild.Cache
```typescript | ||
new codebuild.Project(this, 'Project', { | ||
source: new codebuild.CodePipelineSource(), | ||
cache: Cache.local(LocalCacheMode.DockerLayer) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Show an example with two modes to demonstrate that this is a list
Hi @eladb , I've incorporated all your changes - including the last ones about the docs. Can you take another peek? |
Fixes #1956
Pull Request Checklist
design
folderBy submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license.
BREAKING CHANGE: the CodeBuild Project
cacheBucket
andcacheDir
properties are removed in favour of the newcache
property that allows no caching (default), local caching (new) and S3 caching