Skip to content

Commit

Permalink
feat(AWS Deploy): Ensure consistent function state in deploy function
Browse files Browse the repository at this point in the history
  • Loading branch information
pgrzesik committed Nov 30, 2021
1 parent cc2423b commit d52526b
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 0 deletions.
39 changes: 39 additions & 0 deletions lib/plugins/aws/deployFunction.js
Expand Up @@ -22,6 +22,8 @@ class AwsDeployFunction {
path.join(this.serverless.serviceDir || '.', '.serverless');
this.provider = this.serverless.getProvider('aws');

this.shouldEnsureFunctionState = false;

Object.assign(this, validate);

this.hooks = {
Expand Down Expand Up @@ -76,6 +78,9 @@ class AwsDeployFunction {
await this.deployFunction();
}
await this.updateFunctionConfiguration();
if (this.shouldEnsureFunctionState) {
await this.ensureFunctionState();
}
await this.serverless.pluginManager.spawn('aws:common:cleanupTempDir');
},
};
Expand Down Expand Up @@ -163,6 +168,38 @@ class AwsDeployFunction {
return data.Arn;
}

async ensureFunctionState() {
this.options.functionObj = this.serverless.service.getFunction(this.options.function);
const params = {
FunctionName: this.options.functionObj.name,
};
const startTime = Date.now();

const callWithRetry = async () => {
const result = await this.provider.request('Lambda', 'getFunction', params);
if (
result &&
result.Configuration.State === 'Active' &&
result.Configuration.LastUpdateStatus === 'Successful'
) {
return;
}
const didOneMinutePass = Date.now() - startTime > 60 * 1000;
if (didOneMinutePass) {
throw new ServerlessError(
'Ensuring function state timed out. Please try to deploy your function once again.',
'DEPLOY_FUNCTION_ENSURE_STATE_TIMED_OUT'
);
}
legacy.log(`Retrying ensure function state for function: ${this.options.function}.`);
log.info(`Retrying ensure function state for function: ${this.options.function}.`);
await wait(500);
await callWithRetry();
};

await callWithRetry();
}

async callUpdateFunctionConfiguration(params) {
const startTime = Date.now();

Expand Down Expand Up @@ -389,6 +426,7 @@ class AwsDeployFunction {

mainProgress.notice('Updating function configuration', { isMainEvent: true });
await this.callUpdateFunctionConfiguration(params);
this.shouldEnsureFunctionState = true;
if (this.options['update-config']) log.notice();
log.notice.success(
`Function configuration updated ${style.aside(
Expand Down Expand Up @@ -461,6 +499,7 @@ class AwsDeployFunction {

mainProgress.notice('Deploying', { isMainEvent: true });
await this.provider.request('Lambda', 'updateFunctionCode', params);
this.shouldEnsureFunctionState = true;
legacy.log(`Successfully deployed function: ${this.options.function}`);
log.notice();
log.notice.success(
Expand Down
59 changes: 59 additions & 0 deletions test/unit/lib/plugins/aws/deployFunction.test.js
Expand Up @@ -326,6 +326,8 @@ describe('test/unit/lib/plugins/aws/deployFunction.test.js', () => {
getFunction: {
Configuration: {
LastModified: '2020-05-20T15:34:16.494+0000',
State: 'Active',
LastUpdateStatus: 'Successful',
},
},
updateFunctionCode: updateFunctionCodeStub,
Expand Down Expand Up @@ -408,6 +410,9 @@ describe('test/unit/lib/plugins/aws/deployFunction.test.js', () => {
Configuration: {
LastModified: '2020-05-20T15:34:16.494+0000',
CodeSha256: imageSha,
State: 'Active',
LastUpdateStatus: 'Successful',

ImageConfigResponse: {
ImageConfig: {
Command: ['anotherexecutable'],
Expand Down Expand Up @@ -452,6 +457,8 @@ describe('test/unit/lib/plugins/aws/deployFunction.test.js', () => {
Configuration: {
LastModified: '2020-05-20T15:34:16.494+0000',
CodeSha256: imageSha,
State: 'Active',
LastUpdateStatus: 'Successful',
},
},
},
Expand Down Expand Up @@ -482,6 +489,8 @@ describe('test/unit/lib/plugins/aws/deployFunction.test.js', () => {
Configuration: {
LastModified: '2020-05-20T15:34:16.494+0000',
PackageType: 'Zip',
State: 'Active',
LastUpdateStatus: 'Successful',
},
},
},
Expand Down Expand Up @@ -514,6 +523,8 @@ describe('test/unit/lib/plugins/aws/deployFunction.test.js', () => {
Configuration: {
LastModified: '2020-05-20T15:34:16.494+0000',
PackageType: 'Image',
State: 'Active',
LastUpdateStatus: 'Successful',
},
},
},
Expand Down Expand Up @@ -572,6 +583,8 @@ describe('test/unit/lib/plugins/aws/deployFunction.test.js', () => {
Configuration: {
LastModified: '2020-05-20T15:34:16.494+0000',
PackageType: 'Zip',
State: 'Active',
LastUpdateStatus: 'Successful',
},
},
},
Expand Down Expand Up @@ -644,6 +657,8 @@ describe('test/unit/lib/plugins/aws/deployFunction.test.js', () => {
Configuration: {
LastModified: '2020-05-20T15:34:16.494+0000',
PackageType: 'Zip',
State: 'Active',
LastUpdateStatus: 'Successful',
},
},
},
Expand Down Expand Up @@ -693,6 +708,8 @@ describe('test/unit/lib/plugins/aws/deployFunction.test.js', () => {
Configuration: {
LastModified: '2020-05-20T15:34:16.494+0000',
PackageType: 'Zip',
State: 'Active',
LastUpdateStatus: 'Successful',
},
},
},
Expand Down Expand Up @@ -755,6 +772,9 @@ describe('test/unit/lib/plugins/aws/deployFunction.test.js', () => {
KMSKeyArn: kmsKeyArn,
Description: description,
Handler: handler,
State: 'Active',
LastUpdateStatus: 'Successful',

Environment: {
Variables: {
ANOTHERVAR: 'anothervalue',
Expand Down Expand Up @@ -970,4 +990,43 @@ describe('test/unit/lib/plugins/aws/deployFunction.test.js', () => {
})
).to.be.eventually.rejected.and.have.property('code', 'FUNCTION_NOT_YET_DEPLOYED');
});

it('should handle situation where function is not immediately in desired state', async () => {
const successResponse = {
Configuration: {
LastModified: '2020-05-20T15:34:16.494+0000',
State: 'Active',
LastUpdateStatus: 'Successful',
},
};

const getFunctionStub = sinon
.stub()
.resolves(successResponse)
.onCall(1)
.resolves({
Configuration: {
LastModified: '2020-05-20T15:34:16.494+0000',
State: 'Active',
LastUpdateStatus: 'InProgress',
},
})
.onCall(2)
.resolves(successResponse);

await runServerless({
fixture: 'function',
command: 'deploy function',
options: { function: 'basic' },
lastLifecycleHookName: 'deploy:function:deploy',
awsRequestStubMap: {
...awsRequestStubMap,
Lambda: {
...awsRequestStubMap.Lambda,
getFunction: getFunctionStub,
},
},
});
expect(getFunctionStub).to.have.been.calledThrice;
});
});
2 changes: 2 additions & 0 deletions test/unit/lib/plugins/package/lib/packageService.test.js
Expand Up @@ -359,6 +359,8 @@ describe('test/unit/lib/plugins/package/lib/packageService.test.js', () => {
getFunction: {
Configuration: {
LastModified: '2020-05-20T15:34:16.494+0000',
State: 'Active',
LastUpdateStatus: 'Successful',
},
},
updateFunctionCode: updateFunctionCodeStub,
Expand Down

0 comments on commit d52526b

Please sign in to comment.