diff --git a/src/source-api-association-merge.ts b/src/source-api-association-merge.ts index 76af016..c265551 100644 --- a/src/source-api-association-merge.ts +++ b/src/source-api-association-merge.ts @@ -4,6 +4,7 @@ import { CfnResource, CustomResource, Duration, Stack } from 'aws-cdk-lib'; import { ISourceApiAssociation } from 'aws-cdk-lib/aws-appsync'; import { Effect, PolicyStatement } from 'aws-cdk-lib/aws-iam'; import { Code, Runtime, SingletonFunction } from 'aws-cdk-lib/aws-lambda'; +import { RetentionDays } from 'aws-cdk-lib/aws-logs'; import { Provider } from 'aws-cdk-lib/custom-resources'; import { Construct, IConstruct } from 'constructs'; @@ -43,6 +44,13 @@ export interface SourceApiAssociationMergeOperationProviderProps { * @default Duration.minutes(15) */ readonly totalTimeout?: Duration; + + /** + * The number of days log events are kept in CloudWatch Logs for the schemaMergeLambda and sourceApiStablizationLambda. + * + * @default RetentionDays.INFINITE + */ + readonly logRetention?: RetentionDays; } /** @@ -75,6 +83,7 @@ export class SourceApiAssociationMergeOperationProvider extends Construct implem handler: 'index.onEvent', timeout: Duration.minutes(2), uuid: '6148f39b-95bb-47e7-8a35-40adb8b93a7b', + logRetention: props.logRetention, }); this.sourceApiStablizationLambda = new SingletonFunction(this, 'PollSourceApiMergeLambda', { @@ -83,6 +92,7 @@ export class SourceApiAssociationMergeOperationProvider extends Construct implem handler: 'index.isComplete', timeout: Duration.minutes(2), uuid: '163e01ec-6f29-4bf4-b3b1-11245b00a6bc', + logRetention: props.logRetention, }); const provider = new Provider(this, 'SchemaMergeOperationProvider', { @@ -90,6 +100,7 @@ export class SourceApiAssociationMergeOperationProvider extends Construct implem isCompleteHandler: this.sourceApiStablizationLambda, queryInterval: props.pollingInterval ?? Duration.seconds(5), totalTimeout: props.totalTimeout ?? Duration.minutes(15), + logRetention: props.logRetention, }); this.serviceToken = provider.serviceToken; @@ -127,6 +138,13 @@ export interface SourceApiAssociationMergeOperationProps { */ readonly mergeOperationProvider?: ISourceApiAssociationMergeOperationProvider; + /** + * The default merge operation provider props to use when it is charge of creating a new merge operation provider. + * + * @default { pollingInterval: Duration.seconds(30) } + */ + readonly defaultMergeOperationProviderProps?: SourceApiAssociationMergeOperationProviderProps; + /** * The version identifier for the schema merge operation. Any change to the version identifier will trigger a merge on the next * update. Use the version identifier property to control when the source API metadata is merged. @@ -192,7 +210,7 @@ export class SourceApiAssociationMergeOperation extends Construct { var mergeOperationProvider = props.mergeOperationProvider; if (!mergeOperationProvider) { - mergeOperationProvider = this.getOrCreateMergeOperationProvider(); + mergeOperationProvider = this.getOrCreateMergeOperationProvider(props.defaultMergeOperationProviderProps ?? {}); } mergeOperationProvider.associateSourceApiAssociation(props.sourceApiAssociation); @@ -241,13 +259,14 @@ export class SourceApiAssociationMergeOperation extends Construct { * Get an existing merge operation provider from the current stack or create a new stack scoped merge operation provider. * @returns SourceApiAssociationMergeOperationProvider */ - private getOrCreateMergeOperationProvider(): SourceApiAssociationMergeOperationProvider { + private getOrCreateMergeOperationProvider(props: SourceApiAssociationMergeOperationProviderProps): SourceApiAssociationMergeOperationProvider { const constructName = 'SchemaMergeOperationProvider'; const stack = Stack.of(this); const existing = stack.node.tryFindChild(constructName); if (!existing) { return new SourceApiAssociationMergeOperationProvider(stack, 'SchemaMergeOperationProvider', { pollingInterval: Duration.seconds(30), + ...props, }); } else { return existing as SourceApiAssociationMergeOperationProvider; diff --git a/test/source-api-association-merge.test.ts b/test/source-api-association-merge.test.ts index 9d54b54..3e88be6 100644 --- a/test/source-api-association-merge.test.ts +++ b/test/source-api-association-merge.test.ts @@ -2,6 +2,7 @@ import * as path from 'path'; import { Template } from 'aws-cdk-lib/assertions'; import * as appsync from 'aws-cdk-lib/aws-appsync'; import * as iam from 'aws-cdk-lib/aws-iam'; +import * as logs from 'aws-cdk-lib/aws-logs'; import * as cdk from 'aws-cdk-lib/core'; import { SourceApiAssociationMergeOperation } from '../src'; @@ -112,6 +113,22 @@ test('source api association merge operation with always update', () => { Template.fromStack(stack).resourceCountIs('AWS::Lambda::Function', 5); Template.fromStack(stack).resourceCountIs('Custom::AppSyncSourceApiMergeOperation', 1); + Template.fromStack(stack).resourceCountIs('Custom::LogRetention', 0); +}); + +test('source api association merge operation with logRetention and pollingInterval set', () => { + new SourceApiAssociationMergeOperation(stack, 'SourceApi1Merge', { + sourceApiAssociation: sourceApiAssociation1, + alwaysMergeOnStackUpdate: true, + defaultMergeOperationProviderProps: { + logRetention: logs.RetentionDays.ONE_DAY, + pollingInterval: cdk.Duration.minutes(1), + }, + }); + + Template.fromStack(stack).resourceCountIs('AWS::Lambda::Function', 6); // +1 for log retention cleanup + Template.fromStack(stack).resourceCountIs('Custom::AppSyncSourceApiMergeOperation', 1); + Template.fromStack(stack).resourceCountIs('Custom::LogRetention', 2); }); test('source api association merge operations with version identifier', () => {