-
Notifications
You must be signed in to change notification settings - Fork 4k
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
fix(lambda-nodejs): NodejsFunction construct incompatible with lambda@edge #9562
Conversation
if (edgeLambda.functionVersion.lambda.removeEnvironment()) { | ||
edgeLambda.functionVersion.lambda.node.addWarning(`Removed environment variables from function ${edgeLambda.functionVersion.lambda.node.path} because Lambda@Edge does not support environment variables`); | ||
} |
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 is going to surprise customers who are not aware of this limitation and expect their environment variables to show up.
How about removing environment variables that the CDK inserts, and throwing an error when the customer has environment variables configured?
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.
Also (FYI), the addWarning
API was just deprecated yesterday (#9563) as part of prep work for CDK 2.0 (Design).
In the future, you'd use:
if (edgeLambda.functionVersion.lambda.removeEnvironment()) { | |
edgeLambda.functionVersion.lambda.node.addWarning(`Removed environment variables from function ${edgeLambda.functionVersion.lambda.node.path} because Lambda@Edge does not support environment variables`); | |
} | |
if (edgeLambda.functionVersion.lambda.removeEnvironment()) { | |
Annotations.of(edgeLambda.functionVersion.lambda).addWarning(`Removed environment variables from function ${edgeLambda.functionVersion.lambda.node.path} because Lambda@Edge does not support environment variables`); | |
} |
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.
@nija-at
This means that we need to identify env vars inserted by CDK? You would like to add a special method (addCdkEnvironment()
) and prop (cdkEnvironment
) to identify those? Doesn't it require "developer discipline" inside the CDK?
Also consider the following use case outside the CDK: you have a construct that creates your special Lambda with a defined lists of env vars (whether used in the runtime code or not, like STAGE
for example) and other good defaults. You want to use it both at edge and not.
@njlynch
saw #9563 but unfortunately Annotations
has not been exported in core/lib/index.ts
in this PR. Will be done when all node.addXxx()
methods will be updated in the constructs library I presume.
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 fair @jogold.
In your example, if I understand the lambda@edge limitation correctly, the special lambda function in the construct may not work at edge if it relies on certain env vars being present.
In this case, does it make sense instead to have a property allowInEdgeEnv
or edgeEnvOptimized
or something similar (false
by default), that strips out env vars when used in edge environment, and errors out otherwise?
This can be used to encode similar behaviour for other lambda@edge limitations.
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.
@nija-at how about the following?
- add a
get edgeArn()
getter onIVersion
: in there we can check that the version is "compatible" for Lambda@Edge and throw otherwise, let's start with env vars only in this PR (+ the check that it's not $LATEST) - call this
get edgeArn()
inaws-cloudfront
instead of doinglambdaFunctionArn: edgeLambda.functionVersion.functionArn
=>lambdaFunctionArn: edgeLambda.functionVersion.edgeArn
. - add a third parameter
allowEdgeRemoval
toaddEnvironment()
so that we can loop over the env vars inget edgeArn()
, remove the env vars that we're allowed to and throw if anything remains (with a clear message saying thataddEnvironment()
can be used to overcome it).allowEdgeRemoval
will be set totrue
in the call toaddEnvironment()
inaws-lambda-nodejs
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 approach looks reasonable to me.
Minor tweaks - make the third parameter to addEnvironment()
- EnvironmentOptions
- which holds the property removeInEdge
(or something like that).
/** | ||
* Checks whether this function is compatible for Lambda@Edge. | ||
*/ | ||
checkEdgeCompatibility(): void; |
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 have you added this API to IFunction
? Is there value in exposing this to users?
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.
Because the underlying Lambda of a version is an IFunction
. For the same reason, I had to make checkEdgeCompatibility()
public. Do you see a workaround?
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, I was not able to follow your response. Can you expand a bit more?
If we wanted it to be on a base class so that it's available on all implementations, we could make it a protected abstract method on FunctionBase
and mark it as @internal
?
At the calling point check on instanceof
and call this internal method. We do that in a few places in the CDK, like here.
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.
OK with instanceof
I can move this method to Function
but it will remain public since I need to call it from a Version
on its underlying Lambda?
We don't need this method on FunctionBase
because an imported Lambda will always be considered to be compatible?
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.
If it's moved to FunctionBase
and marked @internal
, keeping it as public
is fine.
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.
Also do you prefer the Symbol
implementation (vs instanceof Function
)?
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 my preference but not strongly.
The value of the symbol based implementation will diminish over the next few months with our upcoming move to monolithic packaging.
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 my preference but not strongly.
Went for the instanceof
implementation because FunctionBase
has currently no constructor
and didn't want to add one.
_checkEdgeCompatibility()
is on FunctionBase
to handle singleton functions.
@@ -760,27 +762,43 @@ export class Function extends FunctionBase { | |||
return this._logGroup; | |||
} | |||
|
|||
public checkEdgeCompatibility(): void { |
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.
Make this private
instead?
Co-authored-by: Niranjan Jayakar <nija@amazon.com>
@@ -426,8 +426,7 @@ nodeunitShim({ | |||
const stack = new cdk.Stack(); | |||
const sourceBucket = new s3.Bucket(stack, 'Bucket'); | |||
|
|||
const lambdaFunction = new lambda.SingletonFunction(stack, '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.
Had to move from a SingletonFunction
to Function
because SingletonFunction
has no addVersion()
it's a FunctionBase
. This test was actually incorrect because it associated a latest version with a CF distribution.
SingletonFunction
now has a _checkEdgeCompatibility()
but no addVersion()
yet, for this 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.
Thanks @jogold - looks good. Just a couple of things below.
I've also reworded the commit title to focus on the NodejsFunction construct since that seems to be the primary benefit of this change.
}; | ||
}) | ||
? this.props.edgeLambdas.map(edgeLambda => ({ | ||
lambdaFunctionArn: Lazy.stringValue({ produce: () => edgeLambda.functionVersion.edgeArn }), |
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.
edgeArn
must always be lazily processed. Would be better to move the Lazy.stringValue()
block into the getter.
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.
Indeed better, 👍
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 master and then merged automatically (do not update manually, and be sure to allow changes to be pushed to your fork). |
…@edge (aws#9562) Check version and function compatibility when a Lambda is used for Lambda@Edge. Environment variables can be marked as "removable" when used for Lambda@Edge. Closes aws#9328 Closes aws#9453 ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
Add `currentVersion` for singleton functions. This makes it possible to use them for Lambda@Edge. Also remove deprecated calls to `addVersion()` introduced in aws#9562.
Add `currentVersion` for singleton functions. This makes it possible to use them for Lambda@Edge. To achieve this, make `ensureLambda()` return a `Function` and not an `IFunction` (which now allows to remove the default implementation of `_checkEdgeCompatibilty()` in `FunctionBase`). Also remove deprecated calls to `addVersion()` introduced in #9562. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
Check version and function compatibility when a Lambda is used for
Lambda@Edge. Environment variables can be marked as "removable" when
used for Lambda@Edge.
Closes #9328
Closes #9453
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license