-
Notifications
You must be signed in to change notification settings - Fork 5.7k
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(AWS Lambda): Add support for image config #8778
feat(AWS Lambda): Add support for image config #8778
Conversation
23c4765
to
f6b1bdc
Compare
Codecov Report
@@ Coverage Diff @@
## master #8778 +/- ##
==========================================
+ Coverage 87.76% 87.80% +0.03%
==========================================
Files 264 264
Lines 9820 9856 +36
==========================================
+ Hits 8619 8654 +35
- Misses 1201 1202 +1
Continue to review full report at Codecov.
|
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.
@pgrzesik looks very good. I have just few minor suggestions.
updating code of function with an image causes subsequent configuration update to fail
It's not clear exactly what do you mean by code of function?
AFAIK with images there's no code updated. We update just configuration properties related to image. Code is specific to regular handler what do I miss?
lib/plugins/aws/provider.js
Outdated
if (imageDefinedInProvider) { | ||
if (_.isObject(imageDefinedInProvider)) { | ||
if (!imageDefinedInProvider.uri && !imageDefinedInProvider.path) { | ||
async function (functionName, image) { |
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.
Let's maybe accept just functionName
argument, as technically then image
is redundant and can be resolved as:
const { image } = this.serverless.service.getFunction(functionName);
lib/plugins/aws/provider.js
Outdated
properties: { | ||
name: { | ||
type: 'string', | ||
pattern: '^[a-z]{1,32}$', |
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'll be nice to reuse imageNamePattern
variable
const modulesCacheStub = { | ||
'child-process-ext/spawn': sinon.stub().resolves(), | ||
}; |
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.
There's dedicated shouldStubSpawn
option, that does just that
}, | ||
}, | ||
}) | ||
).to.be.rejectedWith('Referenced "undefinedimage" not defined in "provider.ecr.images"'); |
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.
Let's test against error codes
f6b1bdc
to
850fef0
Compare
Sorry, I've read what I wrote and it's definitely not clear what I meant. The way it works is that updating That brings a question - how to handle use case when someone wants to deploy such function when also updating it's configuration? I see the following options:
What do you think? |
Thanks for clarification. Does the fail happen in all cases? Even if |
From my observations it looks like it's always failing in such case, even if the |
Will retrying will help? (e.g. we can retry for c.a. 15 seconds) |
I believe it should work, as running it with |
I've adjusted our retry logic in Failing
Success
|
@pgrzesik as I think of it, best DX approach could be to:
It feels complicated, but I guess it secures are really solid experience. What do yo think? |
Thanks @medikoo, I like the approach, we're already fetching results of
What do you think? |
I wonder if it should be a part of However if you feel we can neatly incorporate retrying on specific errors into
It depends. Do you think that what we have currently in master deserves improvements? Or are those improvements preferred now, in context of properties we're adding here. If it's the latter, then it feels as it belongs to this PR |
I was thinking about it too, I've implemented a simple
I believe the current functionality on |
850fef0
to
99bcc58
Compare
In the last commit I added a simplified version of your proposal:
Number 3 should have no effect for regular deploys with Minus the config change checking, what do you think about the approach to implementation? Update: It gets quite messy to actually validate if something changed in the function's |
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 @pgrzesik! I've put some comments under proposed changes.
Unfortunately it's getting a bit more complex, but I guess it's for good. This should ensure really reliable, not flaky, experience
due to the fact that some fields are mapped differently and some of them might be e.g. missing when we removed some properties, e.g. VpcConfig
I assume that function configuration update is patch like operation (?) So AWS will attempt to update only properties which we pass. Is that the case?
If it's so, wouldn't it work only by confirming the properties we intend to pass to function configuration update, whether what's already configured is not the same (?)
Or do values that are coming from AWS, are somewhat normalized and it's hard for use to have solid answer for some?
lib/plugins/aws/deployFunction.js
Outdated
' Please run "serverless deploy" to ensure consistent deploy.', | ||
]; | ||
throw new this.serverless.classes.Error( | ||
errorMessage, |
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 I read correctly it's an array, while what we should pass to ServerlessError
class should be string
(ideally would be simply to provide this error message inline, without arrayifciation and joining - we can simply split string into parts)
lib/plugins/aws/deployFunction.js
Outdated
`The function "${this.options.function}" you want to update with handler was previously packaged as an image.`, | ||
' Please run "serverless deploy" to ensure consistent deploy.', | ||
]; | ||
throw new this.serverless.classes.Error( |
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.
To maintain single convention it'll be nice to always rely on ServerlessError
as required from lib/servelress-error
(altough I know that probably other errors in this file are constructed via classes.Error
- I've opened an issue to cleanup all such instances: #8783)
lib/plugins/aws/deployFunction.js
Outdated
this.serverless.cli.log( | ||
`Retrying update of function: ${this.options.function}. Reason: ${err.message}` | ||
); | ||
await wait(5000); |
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 would do 1s
. I think there's no harm with issuing request more frequently, and we can ensure that way use won't wait too long (5s adds significant overhead)
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 was even considering going higher here, the problem is that it takes ~25-30 seconds in my case to actually succeed with an update and I can imagine it might be even longer for specific use cases. Do you think it's a good approach to issue 25-30 retries under regular circumstances?
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 guess it's not that harmful. Context is most likely that some developer is updating the dev stage, and changed both image uri and some config (but that's to be confirmed I believe). So case is quite rare and should not affect production deployments.
Additionally we have some backoff logic in case of rate limit errors. So it's not that we'll just crash in such case.
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, in general, that case should be quite rare if we have proper checking for configuration update only in case when something really changed.
lib/plugins/aws/deployFunction.js
Outdated
@@ -63,6 +65,35 @@ class AwsDeployFunction { | |||
} | |||
} | |||
|
|||
// TODO: TESTS |
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.
For completeness it'll be nice to address those TODO's. Is this PR in temporary unfinished state?
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 pushed that commit with intention to discuss the approach, it's definitely not in the final state as it's not cleaned up and tested properly
lib/plugins/aws/deployFunction.js
Outdated
async callUpdateFunctionConfiguration(params) { | ||
await this.provider.request('Lambda', 'updateFunctionConfiguration', params); | ||
// TODO: ADD max count? |
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.
We may set some time restriction, e.g. do not go beyond one minute.
lib/plugins/aws/deployFunction.js
Outdated
@@ -244,6 +318,7 @@ class AwsDeployFunction { | |||
|
|||
await this.provider.request('Lambda', 'updateFunctionCode', params); | |||
this.serverless.cli.log(`Successfully deployed function: ${this.options.function}`); | |||
return; |
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 change I guess is not necessary (?)
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 correct, I was toying with checking if the function was deployed or not and returning here bool value
It's exactly the approach I took, but it's a bit messy to properly validate and also error-prone, especially in situations where we're considering |
99bcc58
to
91eb1c9
Compare
I believe most of the points were addressed via: #8786 and I've rebased + added last pieces (checking for |
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 great 👍
Closes: #8583
There's one thing that I'd like to clarify before merging this one. Initially, I've added support for image config for
deploy function
as well, however, as it turns out, updating code of function with an image causes subsequent configuration update to fail (I believe there's some async process triggered on AWS side that updates the function even after the request completes). We could potentially introduce check + warning that when function has an image, configuration update is skipped and if you'd like to update configuration, you have to force it with--update-config
flag. We can also just skip it for now and potentially add support for it later. What do you think @medikoo?