From 12a118c96e7edc13122e621a99921bdfa8627db5 Mon Sep 17 00:00:00 2001 From: Jonathan Goldwasser Date: Thu, 11 Apr 2019 14:54:10 +0200 Subject: [PATCH] fix(lambda): avoid OperationAbortedException when using log retention (#2237) If multiple LogRetention constructs are present in the stack, they will try to act on the provider's log group at the same time. This can sometime result in an OperationAbortedException. To avoid this and because this operation is not critical it is better to catch all errors when acting on the provider's log group --- .../lib/log-retention-provider/index.ts | 13 +++++-- .../test/test.log-retention-provider.ts | 35 +++++++++++++++++++ 2 files changed, 45 insertions(+), 3 deletions(-) diff --git a/packages/@aws-cdk/aws-lambda/lib/log-retention-provider/index.ts b/packages/@aws-cdk/aws-lambda/lib/log-retention-provider/index.ts index 4af3302d74374..56d71ea19cd68 100644 --- a/packages/@aws-cdk/aws-lambda/lib/log-retention-provider/index.ts +++ b/packages/@aws-cdk/aws-lambda/lib/log-retention-provider/index.ts @@ -49,9 +49,16 @@ export async function handler(event: AWSLambda.CloudFormationCustomResourceEvent // group for this function should already exist at this stage because we // already logged the event but due to the async nature of Lambda logging // there could be a race condition. So we also try to create the log group - // of this function first. - await createLogGroupSafe(`/aws/lambda/${context.functionName}`); - await setRetentionPolicy(`/aws/lambda/${context.functionName}`, 1); + // of this function first. If multiple LogRetention constructs are present + // in the stack, they will try to act on this function's log group at the + // same time. This can sometime result in an OperationAbortedException. To + // avoid this and because this operation is not critical we catch all errors. + try { + await createLogGroupSafe(`/aws/lambda/${context.functionName}`); + await setRetentionPolicy(`/aws/lambda/${context.functionName}`, 1); + } catch (e) { + console.log(e); + } } } diff --git a/packages/@aws-cdk/aws-lambda/test/test.log-retention-provider.ts b/packages/@aws-cdk/aws-lambda/test/test.log-retention-provider.ts index 86ced0d4226b7..385f95f1dd613 100644 --- a/packages/@aws-cdk/aws-lambda/test/test.log-retention-provider.ts +++ b/packages/@aws-cdk/aws-lambda/test/test.log-retention-provider.ts @@ -1,3 +1,4 @@ +import AWSSDK = require('aws-sdk'); import AWS = require('aws-sdk-mock'); import nock = require('nock'); import { Test } from 'nodeunit'; @@ -227,4 +228,38 @@ export = { test.done(); }, + + async 'does not fail when operations on provider log group fail'(test: Test) { + const createLogGroupFake = (params: AWSSDK.CloudWatchLogs.CreateLogGroupRequest) => { + if (params.logGroupName === '/aws/lambda/provider') { + return Promise.reject(new Error('OperationAbortedException')); + } + return Promise.resolve({}); + }; + + const putRetentionPolicyFake = sinon.fake.resolves({}); + const deleteRetentionPolicyFake = sinon.fake.resolves({}); + + AWS.mock('CloudWatchLogs', 'createLogGroup', createLogGroupFake); + AWS.mock('CloudWatchLogs', 'putRetentionPolicy', putRetentionPolicyFake); + AWS.mock('CloudWatchLogs', 'deleteRetentionPolicy', deleteRetentionPolicyFake); + + const event = { + ...eventCommon, + RequestType: 'Create', + ResourceProperties: { + ServiceToken: 'token', + RetentionInDays: '30', + LogGroupName: 'group' + } + }; + + const request = createRequest('SUCCESS'); + + await provider.handler(event as AWSLambda.CloudFormationCustomResourceCreateEvent, context); + + test.equal(request.isDone(), true); + + test.done(); + } };