2016-12-13 17 views
0

私はAWS Lambdaサービスでホストされるいくつかのスクリプトに取り組んでいます。私はJSと大丈夫だからNode.jsを選んだが、PythonやJavaを学んだことはない。しかし、私はMySQLデータベースを照会する必要があるので、悪夢であることが証明されており、関数から結果を正しく取得する方法を理解できません。AWS Lambda node.js非同期関数からデータを返す方法は?

だから基本的に私はこれ(私はいくつかのものをカットしましたが、あなたはアイデアを得るべきです)を持っています、そしてこれは私がしたいことのすべてです。私は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を返します(と投げていないため、 )私の主な機能でエラーが発生します。

このような基本的な同期要求をどのように実行できるか理解してください。私は次の変更(私はおそらく、この間違ったを持っている)のようなものを示して非同期メソッドを使用しての「ソリューション」を見てきましたが、私は、これは何が違うのですか見ない

EDIT

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(); 
} 
+0

'行を返す;'や 'リターンret.result;'として前者は「 – bugwheels94

+0

非同期かどうかをすることになっているかどうか、常に関係なく不定になりますreturn ret.result "、更新された質問を表示する...私の戻り値は未定義ではなく、" ret.result "が最初にヌルに設定されているので、常にnullになり、その値が設定される前に関数が戻ります。 – TheBeardedQuack

+0

はあなたが呼び出しは同期になりたいですか、ノードjsの非同期動作を受け入れ、あなたのコードの動作を変更し、代わりに – bugwheels94

答えて

6

JavaScriptのコールバックの基本的な概念が欠落しているようです。

main機能で提供されているcallback引数を使用する必要があります。それがラムダにあなたが戻ってくる結果があることを伝える方法です。 databaseCommandを呼び出すの最後の引数として

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:ここ

はあなたのアイデアを与えるためにあなたのコードのビット簡易版です。これは、connection.queryがDBからいくつかの行をフェッチするときに、ラムダが提供するのと同じコールバックを呼び出すことを意味します。

別の重要な点は、各ラムダ実行時にDB接続を作成しないことです。高いです。関数がフリーズされたときに、変数を一度初期化してから再び初期化することができます。ここをクリックしてください - 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

+0

いいえ、ポインターが毎回接続を設定していないことに感謝します。また、私は、データベースから返されたデータに対して数多くの計算を行い、アマゾンに対する結果はデー​​タベースから返された結果と大きく異なります。私の質問は、データを抽出して返す前に数学を実行できるようにすることです。元の質問を修正して、わからないコールバックについてコードを表示します。 – TheBeardedQuack

+0

@SatsumaBenji返されたDBレスポンスでいくつかの数学を行う方法を示すためのコード例を更新しました –

+0

私はこれが "コールバック地獄"と呼ばれるのを見て、 ONLY **メイン関数に対して非同期的にしか受信できないデータに対して操作を実行し、長い関数の場合、これはネストされたラムダ(または名前付き関数)のロードとロードを引き起こします。 このアマゾンのほかにも、メイン関数が呼び出されずにメイン関数が返された場合には不平を言うようです...コールバック関数の負荷を入れ子にすると、計算を実行できますが、AWSの前に結果を送信することはできません-Lambdaは終了します...これが問題ないかぎり? – TheBeardedQuack

3

AWSラムダアーキテクチャと同様に、非同期実行の仕組みを誤解しているようです。ここにあなたのコードサンプルの修正版は、インラインコメントで、です:

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); 
    }); 
}; 
関連する問題