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

feat(lambda): allow running a build file #30196

Merged
merged 42 commits into from
May 30, 2024
Merged

feat(lambda): allow running a build file #30196

merged 42 commits into from
May 30, 2024

Conversation

bergjaak
Copy link
Contributor

@bergjaak bergjaak commented May 14, 2024

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

  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


By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license

@github-actions github-actions bot added the p2 label May 14, 2024
@aws-cdk-automation aws-cdk-automation requested a review from a team May 14, 2024 21:23
@mergify mergify bot added the contribution/core This is a PR that came from AWS. label May 14, 2024
Copy link
Collaborator

@aws-cdk-automation aws-cdk-automation left a 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.

@github-actions github-actions bot added effort/large Large work item – several weeks of effort feature-request A feature should be added or improved. p1 and removed p2 labels May 14, 2024
@bergjaak bergjaak changed the title Bergjaak/18470 feat(Lambda): allow running a build file May 14, 2024
@bergjaak bergjaak added effort/medium Medium work item – several days of effort and removed effort/large Large work item – several weeks of effort labels May 14, 2024
Comment on lines 114 to 125
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 {
Copy link
Contributor

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}`,
  });
}

Copy link
Contributor Author

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

Copy link
Contributor

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

Copy link
Contributor Author

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.

Copy link
Contributor Author

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

Copy link
Contributor Author

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

Copy link
Contributor

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.

Comment on lines 9 to 16
"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>/**/*" ],
Copy link
Contributor

Choose a reason for hiding this comment

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

leftover?

Copy link
Contributor Author

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

@colifran colifran changed the title feat(Lambda): allow running a build file feat(lambda): allow running a build file May 15, 2024
@github-actions github-actions bot added effort/large Large work item – several weeks of effort and removed effort/medium Medium work item – several days of effort labels May 15, 2024
@colifran colifran added p2 and removed p1 labels May 15, 2024
@@ -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
Copy link
Contributor

Choose a reason for hiding this comment

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

Nice README update!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yay

Copy link
Contributor

@colifran colifran left a 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-cdk-automation
Copy link
Collaborator

AWS CodeBuild CI Report

  • CodeBuild project: AutoBuildv2Project1C6BFA3F-wQm2hXv2jqQv
  • Commit ID: 86c345b
  • Result: SUCCEEDED
  • Build Logs (available for 30 days)

Powered by github-codebuild-logs, available on the AWS Serverless Application Repository

Copy link
Contributor

mergify bot commented May 30, 2024

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).

@mergify mergify bot merged commit 89042c4 into main May 30, 2024
12 checks passed
@mergify mergify bot deleted the bergjaak/18470 branch May 30, 2024 22:33
atanaspam pushed a commit to atanaspam/aws-cdk that referenced this pull request Jun 3, 2024
### 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*
vdahlberg pushed a commit to vdahlberg/aws-cdk that referenced this pull request Jun 10, 2024
### 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*
Leo10Gama pushed a commit to Leo10Gama/aws-cdk that referenced this pull request Jun 11, 2024
### 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*
@aws-cdk-automation
Copy link
Collaborator

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.

@aws aws locked as resolved and limited conversation to collaborators Jul 25, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
contribution/core This is a PR that came from AWS. effort/large Large work item – several weeks of effort feature-request A feature should be added or improved. p1
Projects
None yet
Development

Successfully merging this pull request may close these issues.

(aws-lambda-nodejs): Use esbuild API instead of CLI for bundling
3 participants