javascript - node - Consultar DynamoDB con Lambda no hace nada.
node js dynamodb example (4)
Tengo el siguiente código para una función Lambda:
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();
};
Tengo una tabla [Usuarios] que se define como tal:
{
"cognitoID": { "S": "token" },
"email": { "S": "[email protected]" },
"password": { "S": "somepassword" },
"tos_aggreement": { "BOOL": true },
"userID": { "S": "user1" }
}
Cuando llamo a la función (desde la Consola de AWS o la CLI) puedo ver los mensajes en los registros, pero nunca se llama a la devolución de llamada para getItem ().
Intenté hacer getItem (params) sin devolución de llamada, luego definí las devoluciones de llamada para completar, éxito y fracaso, pero cuando hago el envío (), incluso la devolución de llamada completa tampoco se llama.
Sé que las llamadas son asíncronas y pensé que tal vez, la función lambda estaba terminando antes de que se realizara la consulta y, por lo tanto, la devolución de llamada no se llamaría, pero, agregué un simple bucle estúpido al final de la función y la llamada cronometrada después de 3 segundos, sin que se devuelvan las devoluciones de llamada.
Probé con diferentes funciones batchGetItem, getItem, listTables y scan. El resultado es el mismo, no hay error, pero la función de devolución de llamada nunca se llama.
Apuesto a que si pregunto a dynamoDB sin usar Lambda, obtendré los resultados, así que realmente me pregunto por qué no sucede nada aquí.
Creo un rol para la función y creé una política que permitiría el acceso a las funcionalidades en dynamoDB que necesito pero que no sirven de nada.
La política se ve así:
{ "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": "*" } ] }
Ejecuté la política en el simulador y funcionó como pensé. Sugerencias?
Mi problema es que mi lambda se estaba ejecutando en una VPC para poder conectarse a ElastiCache. Esto hace que las consultas a recursos públicos de Internet como DynamoDB y API Gateway se cuelguen indefinidamente. Tuve que configurar una puerta de enlace NAT dentro de mi VPC para poder acceder a DynamoDB.
Para evitar el infierno de devolución de llamada, utilice Promesas. Hay algunos tutoriales bastante buenos en YouTube por un tipo llamado funfunfunction.
Por lo tanto, resulta que el código es correcto. El problema es que la API dynamodb utiliza todas esas devoluciones de llamada y básicamente la función finaliza ANTES de que se hayan recuperado los datos.
La solución más rápida es eliminar la llamada context.succeed()
y se recuperarán los datos. Por supuesto, usar el módulo async ayudaría y si no quiere usar eso, simplemente agregue un contador o un valor lógico a su devolución de llamada y luego espere hasta que el valor haya cambiado, lo que indica que se ha llamado a la devolución de llamada (qué tipo de succión si lo piensas)
Tuve algunos problemas similares y no encontré muchos recursos útiles. Esto es lo que terminé haciendo. Probablemente alguien más inteligente nos puede decir si esto es lo mejor.
function getHighScores(callback) {
var params = {
TableName : ''sessions'',
ScanFilter: {"score":{"AttributeValueList":[{"N":"0"}], "ComparisonOperator":"GT"}},
};
var dynamo = new AWS.DynamoDB();
dynamo.scan(params, function(err, data) {
if (err) {
console.log (err)
callback(err);
} else {
callback(data.Items);
console.log(data.Items);
}
});
}
getHighScores(function (data) {
console.log(data);
context.succeed(data);
});
En resumen, tener la transferencia de devolución de llamada a través de la función principal a la función más pequeña, permite que la aplicación continúe hasta completar el Dynamo. Mantenga el context.succeed en la función secundaria o continúe con otra función allí.