Here is my regional lambda sdk configuration.
The problem is tableStreamArn it seems:
const globalTableTableName = "my-org-glb-table1"
const regionalTable = Table.fromTableAttributes(this, `Table-${Stack.of(this).region}`, {
tableName: globalTableTableName,
tableStreamArn: `arn:aws:dynamodb:${Stack.of(this).region}:${this.account}:table/${globalTableTableName}/stream/latest` // here !
});
const eventSource = new DynamoEventSource(regionalTable, {
startingPosition: StartingPosition.TRIM_HORIZON,
batchSize: 5,
bisectBatchOnError: true,
retryAttempts: 2
});
lambda1.addEventSource(eventSource);
I can not know what stream the table will have, so my lambda stack fail to deploy.
Having the stream/latest
- would not work:
❌ Deployment failed: Error: The stack named app-my-org-lambda-stack failed creation, it may need to be manually deleted from the AWS console: ROLLBACK_COMPLETE: Resource handler returned message: "Invalid request provided: Stream not found: arn:aws:dynamodb:us-east-1:123456789012:table/app-my-org-glb-table1/stream/latest (Service: Lambda, Status Code: 400, Request ID: e165f9e7-f808-4528-b383-4992861e5aa0)" (RequestToken: d98d6f65-21d1-80b0-4ab3-7a3fc9430268, HandlerErrorCode: InvalidRequest)
Unless I am doing it wrong, I've checked this and that:
That sounds good, but how to make it work?
P.S. I used L1 construct to create global table, and tested that it is deploy-able and stream is on there (with some ARN).
if(stackRegion == PRIMARY_REGION) {
const globalTable = new CfnGlobalTable(this, 'my-org-glb-table1', {
tableName: "my-org-glb-table1",
...
Ok. the idea came from this answer.
How I did this with the CKD, is like that (and btw GPT failed on that):
const globalTableTableName = "my-org-glb-table1"
// getting the stream arn for the table
const streamArnProvider = this.getStreamArnProviderService(props.lambdaStreamArnProviderArn, ecrRepo);
const streamArnResource = new CustomResource(this, 'StreamArnResource', {
serviceToken: streamArnProvider.serviceToken,
properties: {
TableName: globalTableTableName // this is where we pass table name to the lambda
}
});
const streamArn = streamArnResource.getAtt('StreamArn').toString();
const regionalTable = Table.fromTableAttributes(this, `${globalTableTableName}-${Stack.of(this).region}`, {
tableName: globalTableTableName,
tableStreamArn: streamArn
});
where:
private getStreamArnProviderService(streamArnProviderLambdaArn: string, ecrRepo: IRepository): Provider {
const streamArnProviderLambda = lambda.Function.fromFunctionAttributes(this, 'ImportedLambda', {
functionArn: streamArnProviderLambdaArn,
// true, since the Lambda function is in the same environment and we want CDK to manage permissions
sameEnvironment: true
});
return new Provider(this, 'StreamArnProviderService', {
onEventHandler: streamArnProviderLambda,
});
}
Basically by introducing +1 lambda that were getting the ARN from the table's ARN per region.
And the streamArnProviderLambdaArn comes from another stack that crates that streamArnProviderLambda