Reputation: 943
I created a C# Lambda function that is being triggered with a DynamoDB stream. It gets excecuted just fine. However, the StreamRecord of the NewImage value returns no values. The count is 0. What am I doing wrong? I have checked all the AWS documention but this seems more and more like a bug. My below lambda function should work and it should return at least 1 StreamRecord in my example. attributeMap.Count always returns 0 but it should return 1.
public void FunctionHandler(DynamoDBEvent dynamoDbEvent, ILambdaContext context)
{
Console.WriteLine($"Beginning to process {dynamoDbEvent.Records.Count} records...");
foreach (var record in dynamoDbEvent.Records)
{
Console.WriteLine($"Event ID: {record.EventID}");
Console.WriteLine($"Event Name: {record.EventName}");
var attributeMap = record.Dynamodb.NewImage;
if (attributeMap.Count > 0) // If item does not exist, attributeMap.Count will be 0
{
Console.WriteLine(attributeMap["AccountId"].S);
}
}
Console.WriteLine("Stream processing complete.");
}
Upvotes: 1
Views: 3108
Reputation: 943
UPDATE: October, 4th, 2018. I no longer use an admin app. I now use CloudFormation exclusively to create and maintain everyting including full CI/CD pipelines with CodePipelines. This includes all Serverless lamba functions in .NET Core 2.1.
I figured it out. The sucky thing is that AWS Docs do not say anything about this. This was a pain in the ass to find out. For anyone else who might need this information here it is: You have to set the stream view type when you create the DynamoDB stream for the table. Here is a picture for the AWS Console:
However, since I setup all tables via an admin console (in C# Core 2.0), here is how I setup the setup the table including the stream specification and the event source mapping request to the lambda function:
var request = new CreateTableRequest
{
TableName = TABLE_CREATE_ACCOUNT,
AttributeDefinitions = new List<AttributeDefinition>()
{
new AttributeDefinition
{
AttributeName = "CommandId",
AttributeType = ScalarAttributeType.S
}
},
KeySchema = new List<KeySchemaElement>()
{
new KeySchemaElement
{
AttributeName = "CommandId",
KeyType = KeyType.HASH
}
},
ProvisionedThroughput = new ProvisionedThroughput
{
ReadCapacityUnits = 1,
WriteCapacityUnits = 1
},
StreamSpecification = new StreamSpecification
{
StreamEnabled = true,
StreamViewType = StreamViewType.NEW_IMAGE
}
};
try
{
var response = _db.CreateTableAsync(request);
var tableDescription = response.Result.TableDescription;
Console.WriteLine("{1}: {0} ReadCapacityUnits: {2} WriteCapacityUnits: {3}",
tableDescription.TableStatus,
tableDescription.TableName,
tableDescription.ProvisionedThroughput.ReadCapacityUnits,
tableDescription.ProvisionedThroughput.WriteCapacityUnits);
string status = tableDescription.TableStatus;
Console.WriteLine(TABLE_CREATE_ACCOUNT + " - " + status);
WaitUntilTableReady(TABLE_CREATE_ACCOUNT);
// This connects the DynamoDB stream to a lambda function
Console.WriteLine("Creating event source mapping between table stream '"+ TABLE_CREATE_ACCOUNT + "' and lambda 'ProcessCreateAccount'");
var req = new CreateEventSourceMappingRequest
{
BatchSize = 100,
Enabled = true,
EventSourceArn = tableDescription.LatestStreamArn,
FunctionName = "ProcessCreateAccount",
StartingPosition = EventSourcePosition.LATEST
};
var reqResponse =_lambda.CreateEventSourceMappingAsync(req);
Console.WriteLine("Event source mapping state: " + reqResponse.Result.State);
}
catch (AmazonDynamoDBException e)
{
Console.WriteLine("Error creating table '" + TABLE_CREATE_ACCOUNT + "'");
Console.WriteLine("Amazon error code: {0}", string.IsNullOrEmpty(e.ErrorCode) ? "None" : e.ErrorCode);
Console.WriteLine("Exception message: {0}", e.Message);
}
catch (Exception e)
{
Console.WriteLine("Error creating table '" + TABLE_CREATE_ACCOUNT + "'");
Console.WriteLine("Exception message: {0}", e.Message);
}
The key is
StreamViewType = StreamViewType.NEW_IMAGE
That was it.
Upvotes: 3