-
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(lambda): allow running a build file #30196
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.
The pull request linter has failed. See the aws-cdk-automation comment below for failure reasons. If you believe this pull request should receive an exemption, please comment and provide a justification.
A comment requesting an exemption should contain the text Exemption Request
. Additionally, if clarification is needed add Clarification Request
to a comment.
if (props.code !== undefined) { | ||
if (props.handler === undefined) { | ||
throw new Error('Cannot determine handler when `code` property is specified. Use `handler` property to specify a handler.'); | ||
} | ||
|
||
super(scope, id, { | ||
...props, | ||
runtime, | ||
architecture, | ||
depsLockFilePath, | ||
projectRoot, | ||
}), | ||
handler: handler.indexOf('.') !== -1 ? `${handler}` : `index.${handler}`, | ||
}); | ||
code: props.code, | ||
handler: props.handler!, | ||
}); | ||
} else { |
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.
Can you help me understand why we need this new code block here? Why can't we just determine the handler in the same way we are doing it right now? Couldn't we just keep the existing code and do something where if code
is supplied we use it, otherwise we do Bundling.bundle
? So something like:
// Entry and defaults
const entry = path.resolve(findEntry(id, props.entry));
const architecture = props.architecture ?? Architecture.X86_64;
const depsLockFilePath = findLockFile(props.depsLockFilePath);
const projectRoot = props.projectRoot ?? path.dirname(depsLockFilePath);
const handler = props.handler ?? 'handler';
super(scope, id, {
...props,
runtime,
code: props.code ?? Bundling.bundle(scope, {
...props.bundling ?? {},
entry,
runtime,
architecture,
depsLockFilePath,
projectRoot,
}),
handler: handler.indexOf('.') !== -1 ? `${handler}` : `index.${handler}`,
});
}
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.
That's what I originally had, but I think it's a worse customer experience. Because there's nothing forcing the customer to name the file containing the exported handler index
. It's entirely up to the customer to decide how they want to name that file, if they're using the Code.fromCustomCommand
. Therefore, I think this is a better customer experience, even if it's a few more lines of code
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 see where you're coming from but I'm not sure I agree. I think this construct has already established that the expected behavior is we will default the handler if it isn't supplied. Consider a customer that is using the nodejs function and they currently don't supply a handler and just use the default. Now, once this feature is released, they decide to use the new code
property to run a custom build script. However, suddenly they're encountering errors since they don't set a handler. I recognize that it is trivial to just specify a handler, but it is a change from the expectation for the construct as a whole. Additionally, we generally try to avoid properties where we have to do a bunch of validation around if a property is set then another one must also be set. We consider it a bit of an anti-pattern. Our VPC construct is a more extreme example of this, but it shows where this can get to be hard to deal with when we have to start doing a ton of property validation - https://github.com/aws/aws-cdk/blob/main/packages/aws-cdk-lib/aws-ec2/lib/vpc.ts
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.
Now, once this feature is released, they decide to use the new code property to run a custom build script. However, suddenly they're encountering errors since they don't set a handler.
My understanding is, if a customer does switch to using Code.fromCustomCommand and wants an error-free transition with default handler values, then their build script will need to create a file (either in a directory or a zip file) named index.js
with an exported function called handler
. Defaulting to handler
makes sense in this case since it's unlikely that the customer would have changed the name of the function. However, if the customer never knew that the file that contained their lambda code, when deployed to AWS Lambda, was called index.js
(since that's abstracted away by this construct), then wouldn't the customer be confused when their lambda fails to work because their build file didn't output the handler in a file called index.js? That seems more confusing to me. By throwing the Error here, we push the error that the customer may run into much earlier, rather than the customer's lambda failing at runtime after deploying successfully -- which could cause an outage if a customer is deploying directly to production.
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.
basically, to avoid having an outage in production, if a customer is switching to using this Code.fromCustomCommand, the customer would need to know that their build file must output a file called index.js that exports a function called handler. That's not something that I think should be hidden from the customer. By requiring handler, we don't abstract away a detail that could potentially lead to an outage
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 agree that this is more complicated, but the alternative is to push this complexity onto the customer after they've deployed their lambda
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.
Happy to change my mind on this, and with the way you've explained it I agree. Doesn't make sense to let the customer fail during deploy time.
.vscode/launch.json
Outdated
"request": "launch", | ||
"args": ["jest", "--runTestsByPath", "/Users/bergjak/workplace/CDK/aws-cdk/packages/aws-cdk-lib/aws-lambda-nodejs/test/function.test.ts"], | ||
"name": "debug unit test", | ||
"program": "/opt/homebrew/bin/yarn", | ||
"cwd": "/Users/bergjak/workplace/CDK/aws-cdk/packages/aws-cdk-lib", | ||
"console": "integratedTerminal", | ||
"sourceMaps": true, | ||
"skipFiles": [ "<node_internals>/**/*" ], |
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.
leftover?
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.
yeah, I'll remove this in my final revision
@@ -392,3 +392,65 @@ In situtations where this does not work, like Docker-in-Docker setups or when us | |||
}, | |||
}); | |||
``` | |||
|
|||
## Running a custom build script as part of cdk synthesis |
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.
Nice README update!
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.
yay
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.
Nice job with this!
AWS CodeBuild CI Report
Powered by github-codebuild-logs, available on the AWS Serverless Application Repository |
Thank you for contributing! Your pull request will be updated from main and then merged automatically (do not update manually, and be sure to allow changes to be pushed to your fork). |
### Issue # (if applicable) Closes aws#18470 ### Reason for this change This allows customers to execute an arbitrary build script as part of cdk synth, which will enable customer to use esbuild plugins. The rationale for this decision is given the issue that is linked above. ### Description of changes 1. Expose the code field on the `aws-lambda-nodejs` construct, so that customers can specify code in ways other than bundling, which was the default and abstracted away from customers before this change. 2. Add a new static method on Code, namely `Code.fromCustomCommand`. This method takes in the commands to run an arbitrary script during cdk synthesis that the customer provides. The customer also provides the location of the output from the buildscript. Then this output is supplied to a lambda function. ### Description of how you validated changes manual testing (involving inspecting output in the AWS Lambda console and invoking the function), integration tests, and full unit test coverage of new changes. ### Checklist - [X] My code adheres to the [CONTRIBUTING GUIDE](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md) and [DESIGN GUIDELINES](https://github.com/aws/aws-cdk/blob/main/docs/DESIGN_GUIDELINES.md) ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
### Issue # (if applicable) Closes aws#18470 ### Reason for this change This allows customers to execute an arbitrary build script as part of cdk synth, which will enable customer to use esbuild plugins. The rationale for this decision is given the issue that is linked above. ### Description of changes 1. Expose the code field on the `aws-lambda-nodejs` construct, so that customers can specify code in ways other than bundling, which was the default and abstracted away from customers before this change. 2. Add a new static method on Code, namely `Code.fromCustomCommand`. This method takes in the commands to run an arbitrary script during cdk synthesis that the customer provides. The customer also provides the location of the output from the buildscript. Then this output is supplied to a lambda function. ### Description of how you validated changes manual testing (involving inspecting output in the AWS Lambda console and invoking the function), integration tests, and full unit test coverage of new changes. ### Checklist - [X] My code adheres to the [CONTRIBUTING GUIDE](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md) and [DESIGN GUIDELINES](https://github.com/aws/aws-cdk/blob/main/docs/DESIGN_GUIDELINES.md) ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
### Issue # (if applicable) Closes aws#18470 ### Reason for this change This allows customers to execute an arbitrary build script as part of cdk synth, which will enable customer to use esbuild plugins. The rationale for this decision is given the issue that is linked above. ### Description of changes 1. Expose the code field on the `aws-lambda-nodejs` construct, so that customers can specify code in ways other than bundling, which was the default and abstracted away from customers before this change. 2. Add a new static method on Code, namely `Code.fromCustomCommand`. This method takes in the commands to run an arbitrary script during cdk synthesis that the customer provides. The customer also provides the location of the output from the buildscript. Then this output is supplied to a lambda function. ### Description of how you validated changes manual testing (involving inspecting output in the AWS Lambda console and invoking the function), integration tests, and full unit test coverage of new changes. ### Checklist - [X] My code adheres to the [CONTRIBUTING GUIDE](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md) and [DESIGN GUIDELINES](https://github.com/aws/aws-cdk/blob/main/docs/DESIGN_GUIDELINES.md) ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
Comments on closed issues and PRs are hard for our team to see. If you need help, please open a new issue that references this one. |
Issue # (if applicable)
Closes #18470
Reason for this change
This allows customers to execute an arbitrary build script as part of cdk synth, which will enable customer to use esbuild plugins. The rationale for this decision is given the issue that is linked above.
Description of changes
aws-lambda-nodejs
construct, so that customers can specify code in ways other than bundling, which was the default and abstracted away from customers before this change.Code.fromCustomCommand
. This method takes in the commands to run an arbitrary script during cdk synthesis that the customer provides. The customer also provides the location of the output from the buildscript. Then this output is supplied to a lambda function.Description of how you validated changes
manual testing (involving inspecting output in the AWS Lambda console and invoking the function), integration tests, and full unit test coverage of new changes.
Checklist
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license