我创建了4个Lambda函数来处理将写入MySQL表的信息。前三个函数分别只选择,插入和更新MYSQL表记录。
然后我创建了第4个函数来接受记录详细信息作为事件参数的一部分。此函数将首先尝试通过调用第一个lambda函数来选择记录,如果找到它,将使用update lambda函数更新表上的记录。如果找不到,它将调用insert函数来添加记录。我在操作MySQL表的3个函数上使用pool.query。我也使用lambda.invoke从第4个函数调用这三个函数。
通过将记录详细信息作为参数传递,我能够在本地成功测试第4个函数,并且能够成功调用三个Lambda函数并更新mySQL表记录。我遇到的问题是,当我在AWS Lambda中上传函数时,它不会调用这三个函数中的任何一个。我没有在日志中看到任何错误,所以我不知道如何检查问题所在。这是,调用其他函数的代码:
exports.handler = (event, context, callback) => {
var err = null;
var payload = {
qryString : event.qryString,
record: event.updaterecord,
dbConfigPool : event.dbConfigPool
}
var params = {
FunctionName: 'getInventory',
Payload: JSON.stringify(payload)
}
console.log(' before invoke ' + JSON.stringify(params) )
lambda.invoke(params, function(err, data) {
console.log(' aftr invoke ' + JSON.stringify(params) )
if (err) {
console.log('err ' + err, err.stack); // an error occurred
event.message = err + ' query error';
}
else {
console.log('success' + JSON.stringify(data));
console.log(' status code ' + JSON.stringify(data.StatusCode));
console.log(' Payload ' + JSON.stringify(JSON.parse(data.Payload)));
var rowsTemp = JSON.parse(data.Payload);
var rows = rowsTemp.data;
if (!rowsTemp.recordExist) {
console.log('insert')
// Update inventory record only if quantity is not negative
var newQuantity = 0
newQuantity = parseFloat(event.updaterecord.quantity);
if (Math.sign(newQuantity) === 1) {
var payload = {
record: event.updaterecord,
dbConfigPool : event.dbConfigPool
}
console.log('insert' + JSON.stringify(payload));
var params = {
FunctionName: 'insertInventory',
Payload: JSON.stringify(payload)
}
lambda.invoke(params, function(err, data) {
if (err) console.log(err, err.stack); // an error occurred
else console.log(data); // successful response
});
}
}
else {
newQuantity = 0
newQuantity = parseFloat(event.updaterecord.quantity) + parseFloat(rows[0].quantity);
if (Math.sign(newQuantity) === 1) {
event.updaterecord.quantity = newQuantity;
} else {
// Set to zero if the result is negative
event.updaterecord.quantity = 0;
}
console.log('value ' + JSON.stringify(newQuantity) + ' updaterecord' + JSON.stringify(event.updaterecord.quantity) );
var payload = {
qryString : event.qryString,
record: event.updaterecord,
dbConfigPool : event.dbConfigPool
}
console.log('update' + JSON.stringify(payload));
var params = {
FunctionName: 'updateInventory',
Payload: JSON.stringify(payload)
}
console.log(' before invoke ' + JSON.stringify(params) )
lambda.invoke(params, function(err, data) {
console.log(' after invoke ' + JSON.stringify(params) )
if (err) {
console.log('err ' + err, err.stack); // an error occurred
event.message = err + ' query error';
} else {
console.log(data);
} // else
}); // lambda invoke
}
} // successful response
});
console.log(' end of function');
var completed = true;
context.callbackWaitsForEmptyEventLoop = false;
callback(null, completed);
}
如果代码很长,请道歉。但我想表明我确实放了一些console.log来监控经过的地方。 cloudwatch日志仅显示第一个lambda.invoke之前的第一条消息,然后显示该函数结束的最后一条消息。
我也没有在cloudwatch中看到已调用的三个函数的任何日志条目。
06/17 好的,因为我仍然无法完成这项工作,我将代码简化为以下内容:
exports.handler = (event, context, callback) => {
var err = null;
var updatedRecord = false;
var responseDetail = {};
var payload = {
qryString : event.qryString,
record: event.updaterecord,
dbConfigPool : event.dbConfigPool
}
var params = {
FunctionName: 'getInventory',
Payload: JSON.stringify(payload)
}
console.log(' before invoke ' + JSON.stringify(params));
lambda.invoke(params, function(err, data) {
if (err) {
event.message = err + ' query error';
callback(err,event.message);
}
else {
console.log('success' + JSON.stringify(data));
console.log(' status code ' + JSON.stringify(data.StatusCode));
console.log(' Payload ' + JSON.stringify(JSON.parse(data.Payload)));
callback(null, data);
} // successful response
});
console.log(' end of function');
// var completed = true;
// context.callbackWaitsForEmptyEventLoop = false;
// callback(null, completed);
}
然而,当我进行测试时,该功能会超时。我还赋予了函数完整的Lambda和RDS访问权限。
答案 0 :(得分:5)
首先 - 欢迎回调地狱!我稍后会回到这里。
这是一个调用lambda函数的简单代码。
var params = {
FunctionName: 'LAMBDA_FUNCTION_NAME', /* required */
};
lambda.invoke(params, function(err, data) {
if (err) {
console.log(err, err.stack); // an error occurred
}
else {
console.log(data); // successful response
}
});
lambda.invoke 函数有两个参数(参数,函数(错误,数据){..} )。第一个是简单的JSON对象。第二个是函数 - 回调函数。当lambda.invoke(您可以认为LAMBDA_FUNCTION_NAME)的执行结束时,此函数将被“回调”。如果发生错误,它将“存储”在错误变量中,否则返回的数据将存储在数据变量中(这不是正确的解释,但我试图保留它这里很简单。)
当你想一个接一个地调用两个lambda函数时会发生什么?
var params1 = {
FunctionName: 'LAMBDA_FUNCTION_1_NAME', /* required */
};
lambda.invoke(params1, function(err, data) {
if (err) {
console.log(err, err.stack); // an error occurred
}
else {
console.log('Lambda function 1 invoked!');
console.log(data); // successful response
}
});
var params2 = {
FunctionName: 'LAMBDA_FUNCTION_2_NAME', /* required */
};
lambda.invoke(params2, function(err, data) {
if (err) {
console.log(err, err.stack); // an error occurred
}
else {
console.log('Lambda function 2 invoked!');
console.log(data); // successful response
}
});
console.log('I am done!');
根据LAMBDA_FUNCTION_1_NAME和LAMBDA_FUNCTION_2_NAME的执行时间,您可以看到不同的输出,例如:
Lambda function 1 invoked!
I am done!
或
Lambda function 1 invoked!
Lambda function 2 invoked!
I am done!
甚至
Lambda function 1 invoked!
I am done!
Lambda function 2 invoked!
这是因为你正在调用lambda.invoke,之后(不等待)你再次调用lambda.invoke。之后(当然没有等待)以前的函数结束你正在调用console.log('我完成了!');
你可以通过将每个函数放在上一个函数的回调中来解决这个问题。像这样:
var params1 = {
FunctionName: 'LAMBDA_FUNCTION_1_NAME', /* required */
};
lambda.invoke(params1, function(err, data) {
if (err) {
console.log(err, err.stack); // an error occurred
}
else {
console.log('Lambda function 1 invoked!');
console.log(data); // successful response
var params2 = {
FunctionName: 'LAMBDA_FUNCTION_2_NAME', /* required */
};
lambda.invoke(params2, function(err, data) {
if (err) {
console.log(err, err.stack); // an error occurred
}
else {
console.log('Lambda function 2 invoked!');
console.log(data); // successful response
console.log('I am done!');
}
});
}
});
那样你的输出就是:
Lambda function 1 invoked!
Lambda function 2 invoked!
I am done!
但是如果你想一个接一个地调用3个或更多个函数,你最终会得到嵌套代码。这是回调地狱。您可以用这种方式重新编写代码。但在我看来,检查waterfall async library
是个好主意async.waterfall([
function(callback) {
callback(null, 'one', 'two');
},
function(arg1, arg2, callback) {
// arg1 now equals 'one' and arg2 now equals 'two'
callback(null, 'three');
},
function(arg1, callback) {
// arg1 now equals 'three'
callback(null, 'done');
}
], function (err, result) {
// result now equals 'done'
})
伪代码应如下所示:
async.waterfall([
function(callback1) {
var params1 = {
FunctionName: 'LAMBDA_FUNCTION_1_NAME', /* required */
};
lambda.invoke(params1, function(err, data) {
if (err) {
console.log(err, err.stack); // an error occurred
}
else {
console.log('LAMBDA_FUNCTION_1_NAME finished!');
callback1(null,data);
}
});
},
function(result_from_function_1, callback2) {
console.log(result_from_function_1); // outputs result from LAMBDA_FUNCTION_1_NAME
var params2 = {
FunctionName: 'LAMBDA_FUNCTION_2_NAME', /* required */
};
lambda.invoke(params2, function(err, data) {
if (err) {
console.log(err, err.stack); // an error occurred
}
else {
console.log('LAMBDA_FUNCTION_2_NAME finished!');
callback2(null,data);
}
});
},
function(result_from_function_2, callback3) {
console.log(result_from_function_2); // outputs result from LAMBDA_FUNCTION_2_NAME
var params3 = {
FunctionName: 'LAMBDA_FUNCTION_3_NAME', /* required */
};
lambda.invoke(params3, function(err, data) {
if (err) {
console.log(err, err.stack); // an error occurred
}
else {
console.log('LAMBDA_FUNCTION_3_NAME finished!');
callback3(null,data);
}
});
}
], function (err, result) {
// result now equals LAMBDA_FUNCTION_3_NAME result
})
请注意,所有回调(callback1,callback2和callback3)都只能使用名称“callback”。为了更好的理解,我改了名字。
答案 1 :(得分:1)
想想这是做什么的:
lambda.invoke(params, function(err, data) { ...
它开始“做某事”(恰好调用另一个lambda函数的事实实际上并不重要)当“某事”完成时,它会调用function(),对吗?
但它也会立即返回,并执行下一个语句。
同时异步事件循环正在处理“某事”。
“下一个声明”是
console.log(' end of function');
然后,你告诉lambda“嘿,我可能会有一些异步的东西,但不要担心等待它完成”:
context.callbackWaitsForEmptyEventLoop = false;
所以好消息是你的代码正在做着写的事情......但事实证明这是错误的。
你到处都有这两件事之一......
// an error occurred
// successful response
... 那些是你应该调用callback()
的地方,而不是处理程序函数的末尾,你的代码很快就会到达,就像它应该的那样。< / p>
如果正确断开数据库连接并且所包含的所有模块都表现良好,则不需要使用context.callbackWaitsForEmptyEventLoop = false;
。虽然这有其目的,但似乎有很多人用它来掩盖微妙的未完成的业务。
或者,对于一个更整洁的解决方案,你最后只提到一个回调函数和函数{function {function {nesting不会失控,请使用async-waterfall
。