![](/img/trans.png)
[英]AWS lambda function -how to get R script to run from node.js lambda function?
[英]How to return data from AWS Lambda node.js asynchronous function?
我正在研究要在AWS Lambda服務上托管的一些腳本。 我之所以選擇Node.js是因為我對JS沒問題,但我還沒有學習過Python或Java。 但是事實證明這是一場噩夢,因為我需要查詢一個MySQL數據庫,而我卻無法弄清楚如何正確地從函數中獲取結果。
所以基本上我有這樣的事情(我已經刪掉了一些東西,但是你應該明白了),這就是我要做的。 我希望能夠查詢MySQL數據庫,當它有答案時,只需將其返回或在出現錯誤時拋出。
var mysql = require("mysql"); //npm installed module "mysql"
var err = require("./errors.js"); //internally requires npm installed module "errors"
var main = function(event, context, callback){
try{
//Confidential
var data = null;
//Confidential
try{
data = databaseCommand("SELECT * FROM `<table>` WHERE <field> = <value>");
}
catch(e){
if(e instanceof err.Database)
//Return state that indicates "Internal server error".
else
throw e;
return
}
//Do maths on data
//Return "OK" and result
}
catch(e){
//Return "Unkown error"
}
};
var databaseCommand = function(cmdString){
if(typeof cmdString !== "string") throw new err.InputInvalidType({explanation: "'cmdString' is of type '" + typeof cmdString + "', expected type 'string'"});
var connection = mysql.createConnection({
host: process.env.db_host,
port: process.env.db_port || 3306,
user: process.env.db_username,
password: process.env.db_password,
database: process.env.db_database
});
var ret = {
error: null,
result: null
};
//I cut out the connection.connect() because it can be implied and I'm confused enough
connection.query(cmdString, function(error, rows){
if(error)
ret.error = error;
else
ret.result = rows;
});
connection.end();
if(ret.error)
throw new err.Database();
return ret.result;
};
但是對於那些精通Node.js的人來說,這顯然是行不通的,因為對connection.query的調用是異步的,因此我的databaseCommand函數始終返回null(並且不會拋出),並在我的main函數中引起錯誤。
請幫助我了解如何執行這樣的基本同步請求。
編輯
我已經看到了使用異步方法,顯示類似的“解決方案”(我可能都有這個毛病)以下的變化,但我看不出這是任何不同。
var mysql = require("mysql"); //npm installed module "mysql"
var err = require("./errors.js"); //internally requires npm installed module "errors"
var main = function(event, context, callback){
try{
//Confidential
var data = null;
//Confidential
try{
databaseCommand("SELECT * FROM `<table>` WHERE <field> = <value>", function(err, result){
if(err)
throw err;
data = result;
});
//This function will still return before data is set
//Maths will still be performed before data is set
}
catch(e){
if(e instanceof err.Database)
//Return state that indicates "Internal server error".
else
throw e;
return
}
//Do maths on data
//Return result
}
catch(e){
//Return "Unkown error"
}
}
var databaseCommand = function(cmdString, callback){
if(typeof cmdString !== "string") throw new err.InputInvalidType({explanation: "'cmdString' is of type '" + typeof cmdString + "', expected type 'string'"});
var connection = mysql.createConnection({
host: process.env.db_host,
port: process.env.db_port || 3306,
user: process.env.db_username,
password: process.env.db_password,
database: process.env.db_database
});
var ret = {
error: null,
result: null
};
//I cut out the connection.connect() because it can be implied and I'm confused enough
connection.query(cmdString, function(error, rows){
if(error)
callback(err, null);
else
callback(null, rows);
});
connection.end();
}
似乎您缺少JavaScript回調的基本概念。
您必須利用main
函數中提供的callback
參數。 這就是您告訴Lambda您要返回一些結果的方式。
這是您的代碼的簡化版本,可以幫助您:
var mysql = require("mysql"); //npm installed module "mysql"
var err = require("./errors.js"); //internally requires npm installed module "errors"
var connection;
var main = function(event, context, callback) {
databaseCommand("SELECT * FROM `<table>` WHERE <field> = <value>", (error, rows) => {
if (error) return callback(error);
var results = doSomeMathWithRows(rows);
callback(null, results);
});
};
var databaseCommand = function(cmdString, callback) {
if (typeof cmdString !== "string") throw new err.InputInvalidType({
explanation: "'cmdString' is of type '" + typeof cmdString + "', expected type 'string'"
});
// Don't init DB connection for every request
// Lambda functions can lose it only after freezing (see docs for details when)
// so we create connection only on demand
if (!connection) {
connection = mysql.createConnection({
host: process.env.db_host,
port: process.env.db_port || 3306,
user: process.env.db_username,
password: process.env.db_password,
database: process.env.db_database
});
}
connection.query(cmdString, callback);
};
注意, callback
是調用databaseCommand
的最后一個參數。 這意味着,當connection.query
從數據庫中獲取某些行時,它將調用Lambda提供的相同回調。
另一個要點是不要在每個Lambda執行上創建數據庫連接。 它的價格昂貴。 您可以一次初始化變量,然后在凍結函數時再次初始化。 在此處了解更多信息-https: //aws.amazon.com/blogs/compute/container-reuse-in-lambda/
讓我知道它是否對您有用,因為我無需任何檢查即可在線編輯此代碼。 但希望您明白這一點。 您可以在此處了解更多有關如何編寫處理函數的信息: http : //docs.aws.amazon.com/lambda/latest/dg/nodejs-prog-model-handler.html?shortFooter=true
您似乎誤會了異步執行以及AWS Lambda架構的工作方式。 這是代碼示例的修改后的版本,帶有內聯注釋:
var mysql = require("mysql"); //npm installed module "mysql"
// This would be the exported handler function that gets invoked when your AWS Lambda function is triggered
exports.queryDbHandler = function(event, context, callback) {
try {
// This function executes an asynchronous operation so you need to pass in a callback that will be executed once it's done
databaseCommand("SELECT * FROM `<table>` WHERE <field> = <value>", function onData(error, dbData) {
// Once the callback is executed, you call the callback provided to your Lambda function. First argument is an error and the second is payload/result of the operation. First argument should be null if all went ok
if (error) {
callback(error);
} else {
let dbDataProcessed = // do something to dbData
callback(null, dbDataProcessed);
}
});
}
catch(e) {
// In case you had an exception in the synchronous part of the code, you still need to invoke the callback and provide an error
callback(e);
}
}
var databaseCommand = function(cmdString, onResultCallback){
// Instead of throwing, it would be better to just invoke the callback and provide an error object
if(typeof cmdString !== "string") throw new err.InputInvalidType({explanation: "'cmdString' is of type '" + typeof cmdString + "', expected type 'string'"});
var connection = mysql.createConnection({
host: process.env.db_host,
port: process.env.db_port || 3306,
user: process.env.db_username,
password: process.env.db_password,
database: process.env.db_database
});
connection.query(cmdString, function(error, rows) {
// Once we have the data, or an error happened, invoke the callback
onResultCallback(error, rows);
});
};
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.