From ae47336c5d415f2cd6337b7e43b4ecc0449ef610 Mon Sep 17 00:00:00 2001 From: Lee Hannigan Date: Tue, 15 Oct 2024 17:10:33 +0100 Subject: [PATCH] Adding kinesis timestamp precision --- .../aws-cdk-lib/aws-dynamodb/lib/shared.ts | 17 ++++++ .../aws-cdk-lib/aws-dynamodb/lib/table-v2.ts | 20 +++++-- .../aws-dynamodb/test/table-v2.test.ts | 54 +++++++++++++++++++ 3 files changed, 87 insertions(+), 4 deletions(-) diff --git a/packages/aws-cdk-lib/aws-dynamodb/lib/shared.ts b/packages/aws-cdk-lib/aws-dynamodb/lib/shared.ts index 1955ef7fccd35..eb88215a79502 100644 --- a/packages/aws-cdk-lib/aws-dynamodb/lib/shared.ts +++ b/packages/aws-cdk-lib/aws-dynamodb/lib/shared.ts @@ -218,6 +218,23 @@ export enum StreamViewType { KEYS_ONLY = 'KEYS_ONLY', } +/** + * The precision associated with the DynamoDB write timestamps that will be replicated to Kinesis. + * The default setting for record timestamp precision is microseconds. You can change this setting at any time. + * @see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-dynamodb-table-kinesisstreamspecification.html#aws-properties-dynamodb-table-kinesisstreamspecification-properties + */ +export enum ApproximateCreationDateTimePrecision { + /** + * Millisecond precision + */ + MILLISECOND = 'MILLISECOND', + + /** + * Microsecond precision + */ + MICROSECOND = 'MICROSECOND', +} + /** * Properties for a secondary index */ diff --git a/packages/aws-cdk-lib/aws-dynamodb/lib/table-v2.ts b/packages/aws-cdk-lib/aws-dynamodb/lib/table-v2.ts index 65e3c588968e5..e47149441b348 100644 --- a/packages/aws-cdk-lib/aws-dynamodb/lib/table-v2.ts +++ b/packages/aws-cdk-lib/aws-dynamodb/lib/table-v2.ts @@ -4,7 +4,7 @@ import { Capacity } from './capacity'; import { CfnGlobalTable } from './dynamodb.generated'; import { TableEncryptionV2 } from './encryption'; import { - StreamViewType, + StreamViewType, ApproximateCreationDateTimePrecision, Attribute, TableClass, LocalSecondaryIndexProps, SecondaryIndexProps, BillingMode, ProjectionType, } from './shared'; @@ -143,6 +143,13 @@ export interface TableOptionsV2 { */ readonly kinesisStream?: IStream; + /** + * Kinesis Data Stream approximate creation timestamp prescision + * + * @default ApproximateCreationDateTimePrecision.MICROSECOND + */ + readonly kinesisPrecisionTimestamp?: ApproximateCreationDateTimePrecision; + /** * Tags to be applied to the table or replica table * @@ -665,6 +672,12 @@ export class TableV2 extends TableBaseV2 { const pointInTimeRecovery = props.pointInTimeRecovery ?? this.tableOptions.pointInTimeRecovery; const contributorInsights = props.contributorInsights ?? this.tableOptions.contributorInsights; const resourcePolicy = props.resourcePolicy ?? this.tableOptions.resourcePolicy; + const kinesisStreamSpecification = props.kinesisStream + ? { + streamArn: props.kinesisStream.streamArn, + ...(props.kinesisPrecisionTimestamp && { approximateCreationDateTimePrecision: props.kinesisPrecisionTimestamp }), + } + : undefined; return { region: props.region, @@ -672,9 +685,7 @@ export class TableV2 extends TableBaseV2 { deletionProtectionEnabled: props.deletionProtection ?? this.tableOptions.deletionProtection, tableClass: props.tableClass ?? this.tableOptions.tableClass, sseSpecification: this.encryption?._renderReplicaSseSpecification(this, props.region), - kinesisStreamSpecification: props.kinesisStream - ? { streamArn: props.kinesisStream.streamArn } - : undefined, + kinesisStreamSpecification: kinesisStreamSpecification, contributorInsightsSpecification: contributorInsights !== undefined ? { enabled: contributorInsights } : undefined, @@ -810,6 +821,7 @@ export class TableV2 extends TableBaseV2 { replicaTables.push(this.configureReplicaTable({ region: this.stack.region, kinesisStream: this.tableOptions.kinesisStream, + kinesisPrecisionTimestamp: this.tableOptions.kinesisPrecisionTimestamp, tags: this.tableOptions.tags, })); diff --git a/packages/aws-cdk-lib/aws-dynamodb/test/table-v2.test.ts b/packages/aws-cdk-lib/aws-dynamodb/test/table-v2.test.ts index 63bbf3319b73e..98c8ba0217ccf 100644 --- a/packages/aws-cdk-lib/aws-dynamodb/test/table-v2.test.ts +++ b/packages/aws-cdk-lib/aws-dynamodb/test/table-v2.test.ts @@ -6,6 +6,7 @@ import { CfnDeletionPolicy, Lazy, RemovalPolicy, Stack } from '../../core'; import { AttributeType, Billing, Capacity, GlobalSecondaryIndexPropsV2, TableV2, LocalSecondaryIndexProps, ProjectionType, StreamViewType, TableClass, TableEncryptionV2, + ApproximateCreationDateTimePrecision, } from '../lib'; describe('table', () => { @@ -1342,6 +1343,59 @@ describe('replica tables', () => { }); }); + test('with per-replica kinesis stream with precision creation timestamp', () => { + // GIVEN + const stack = new Stack(undefined, 'Stack', { env: { region: 'us-west-2' } }); + const kinesisStream1 = new Stream(stack, 'Stream1'); + const kinesisStream2 = Stream.fromStreamArn(stack, 'Stream2', 'arn:aws:kinesis:us-east-1:123456789012:stream/my-stream'); + + // WHEN + new TableV2(stack, 'GlobalTable', { + partitionKey: { name: 'pk', type: AttributeType.STRING }, + kinesisStream: kinesisStream1, + kinesisPrecisionTimestamp: ApproximateCreationDateTimePrecision.MICROSECOND, + replicas: [ + { + region: 'us-east-1', + kinesisStream: kinesisStream2, + kinesisPrecisionTimestamp: ApproximateCreationDateTimePrecision.MILLISECOND, + }, + { + region: 'us-east-2', + }, + ], + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::DynamoDB::GlobalTable', { + Replicas: [ + { + Region: 'us-east-1', + KinesisStreamSpecification: { + StreamArn: 'arn:aws:kinesis:us-east-1:123456789012:stream/my-stream', + ApproximateCreationDateTimePrecision: 'MILLISECOND', + }, + }, + { + Region: 'us-east-2', + KinesisStreamSpecification: Match.absent(), + }, + { + Region: 'us-west-2', + KinesisStreamSpecification: { + StreamArn: { + 'Fn::GetAtt': [ + 'Stream16C8F97AF', + 'Arn', + ], + }, + ApproximateCreationDateTimePrecision: 'MICROSECOND', + }, + }, + ], + }); + }); + test('with per-replica contributor insights on global secondary index', () => { // GIVEN const stack = new Stack(undefined, 'Stack', { env: { region: 'us-west-2' } });