E.T E.T - 4 months ago 68
Node.js Question

Querying DynamoDB with Lambda does nothing

I have the following code for a Lambda function:

console.log('Loading function');
var aws = require('aws-sdk');
var ddb = new aws.DynamoDB();

function getUser(userid) {
var q = ddb.getItem({
TableName: "Users",
Key: {
userID: { S: userid } }
}, function(err, data) {
if (err) {
console.log(err);
return err;
}
else {
console.log(data);
}
});
console.log(q);
}


exports.handler = function(event, context) {
console.log('Received event');
getUser('user1');
console.log("called DynamoDB");
context.succeed();
};


I have a [Users] table that is defined as such:

{
"cognitoID": { "S": "token" },
"email": { "S": "user1@domain.com" },
"password": { "S": "somepassword" },
"tos_aggreement": { "BOOL": true },
"userID": { "S": "user1" }
}


When I call the function (from the AWS Console or the CLI) I can see the messages in the logs but the callback for the getItem() is never called.

I tried with doing getItem(params) with no callback, then defined the callbacks for complete, success and failure but when I do the send(), even the complete callback isn't called either.

I know that the calls are asynchronous and I thought that maybe, the lambda function was finishing before the query was done and therefore the callback would not be called, but, I added a simple stupid loop at the end of the function and the call timed out after 3 seconds, without the callbacks being called at all.

I tried with different functions batchGetItem, getItem, listTables and scan. Result is the same, no error but the callback function is never called.

I'm betting that if I query dynamoDB without using Lambda it will get me the results so I'm really wondering why nothing is happening here.

I create a role for the function and I created a policy that would allow access to the functionalities in dynamoDB that I need but to no avail.

The policy looks like this:


{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"lambda:InvokeFunction"
],
"Resource": "arn:aws:lambda:*:*:*"
},
{
"Effect": "Allow",
"Action": [
"dynamodb:GetItem",
"dynamodb:BatchGetItem",
"dynamodb:Scan",
"dynamodb:PutItem",
"dynamodb:Query",
"dynamodb:GetRecords",
"dynamodb:ListTables"
],
"Resource": "arn:aws:dynamodb:*:*:*"
},
{
"Action": [
"logs:*"
],
"Effect": "Allow",
"Resource": "*"
}
]
}



I ran the policy in the simulator and it worked as I thought it would.
Suggestions?

E.T E.T
Answer

So, it turns out that the code is correct. The problem is that the dynamodb API uses all those callbacks and basically the function ends BEFORE the data has been retrieved.

The quickest fix is to remove the context.succeed() call and the data will be retrieved. Of course using the async module would help and if you don't want to use that, just add a counter or a boolean to your callback and then wait until the value has changed, indicating that the callback has been called (which kind of sucks if you think of it)