AWS Lambda RDS连接超时

时间:2017-03-05 06:07:36

标签: node.js amazon-web-services aws-lambda rds

我尝试使用连接到我的RDS数据库的Node.js编写Lambda函数。数据库正在运行,可从我的Elastic Beanstalk环境访问。当我运行该函数时,它返回一个超时错误。

尝试使用完全相同的结果将超时时间增加到5分钟。

经过一些研究后我得出的结论是,它可能是一个安全问题,但无法在亚马逊的文档或this答案中找到解决方案(这是我只能在这个主题上找到一个。)

以下是安全细节:

  • RDS和Lambda都在同一个安全组中。
  • RDS具有所有流量入站和出站规则。
  • Lambda拥有AmazonVPCFullAccess政策。

我的代码是:

'use strict';
console.log("Loading getContacts function");

var AWS = require('aws-sdk');
var mysql = require('mysql');

exports.handler = (event, context, callback) => {

   var connection = mysql.createConnection({
        host     : '...',
        user     : '...',
        password : '...',
        port     : 3306,
        database: 'ebdb',
        debug    :  false
    });

    connection.connect(function(err) {
      if (err) callback(null, 'error ' +err);
      else callback(null, 'Success');
    });

};

我得到的结果是:

"errorMessage": "2017-03-05T05:57:46.851Z 9ae64c49-0168-11e7-b49a-a1e77ae6f56c Task timed out after 10.00 seconds"

9 个答案:

答案 0 :(得分:23)

虽然使用上下文会起作用,但您只需要将context.callbackWaitsForEmptyEventLoop = false;添加到处理程序中,然后像往常一样使用回调:

exports.handler = (event, context) => {
  context.callbackWaitsForEmptyEventLoop = false; 
  var connection = mysql.createConnection({
    //connection info
  });
  connection.connect(function(err) {
    if (err) callback(err); 
    else callback(null, 'Success');
  });
};

答案在文档中(我花了几个小时才发现这个): http://docs.aws.amazon.com/lambda/latest/dg/nodejs-prog-model-using-old-runtime.html

在“比较上下文和回调方法”一节中,它有一个解释内容的“重要”注释。

在备注的底部显示:

  

因此,如果您希望与上下文方法具有相同的行为,则必须将上下文对象属性callbackWaitsForEmptyEventLoop设置为false。

基本上,回调继续到事件循环结束,而不是结束事件循环的上下文。因此,设置callbackWaitsForEmptyEventLoop会使回调像上下文一样工作。

答案 1 :(得分:9)

我要感谢所有帮助过的人,问题结果与我想的不同。代码中的callback由于某种原因不起作用,即使它是在AMAZON自己的默认样本中。

工作代码如下所示:

'use strict';
console.log("Loading getContacts function");

var AWS = require('aws-sdk');
var mysql = require('mysql');

exports.handler = (event, context) => {

   var connection = mysql.createConnection({
        host     : '...',
        user     : '...',
        password : '...',
        port     : 3306,
        database: 'ebdb',
        debug    :  false
    });

    connection.connect(function(err) {
      if (err) context.fail();
      else context.succeed('Success');
    });

};

答案 2 :(得分:4)

  
    
      

RDS和Lambda都在同一个安全组中。

    
  

这是关键。默认情况下,不允许在同一安全组内进行通信。你需要明确允许它(E.x sg-xxxxx ALL TCP)。只有当你的lambda尝试通过私有ip访问db时,这才有效。

如果它试图通过公共IP访问它,它将无法工作,你也需要为此打出必要的整体。

然而,有更好的方法:

  1. 为lambda创建单独的单独安全组
  2. 允许RDS sg中端口3306上的入站流量用于lambdas sg。

答案 3 :(得分:2)

我在分享连接RDS时的经验。

  

您需要为VPC启用Lambda function访问权限,在此期间您将为其分配Security Group

然后,在分配给RDS实例的安全组中,您将启用对分配给Lambda函数的安全组的访问。

您可以获得更多信息here

答案 4 :(得分:2)

最初设置数据库时,它会自动创建一个安全组。默认为您设置数据库的IP。当您从lambda运行时,此规则会阻止流量。查看您的db错误日志,您可以确认它是拒绝连接。

***** could not be resolved: Name or service not known

您需要在安全组中创建规则以允许lambda流量。转到RDS实例控制台并单击安全组,选择入站。在那里你会看到规则。然后拨打电话向全世界开放,查找AWS lambda IP或创建VPC。

答案 5 :(得分:1)

我花了大约 2 天的时间才弄清楚确切的问题。就我而言,RDS 和 Lambda 函数都在同一 VPC、子网和安全组中,并添加了必需的角色,但仍然收到套接字超时异常。我能够通过按照以下链接更改入站和出站规则来解决该问题 -

https://aws.amazon.com/premiumsupport/knowledge-center/connect-lambda-to-an-rds-instance/

答案 6 :(得分:0)

问题不是来自超时,而是来自关闭连接的方式。如果您不想在.destroy()

中关闭连接时等待回调或正确使用回调,请使用.end(function(err) { //Now call your callback });

有关更深入的解释,请参阅this thread

答案 7 :(得分:0)

我也遇到过类似的超时情况。 connection.end()之后问题没有connection.connect()Connection.end()应在callback之前完成。

工作代码:

  var mysql = require('mysql');

    var connection = mysql.createConnection({
        host     : 'host_name',
        user     : 'root',
        password : 'password'
    });


    module.exports.handler = (event, context, callback) => {

// **Connection to database**      
connection.connect(function(err) {
        if (err) {
          console.error('Database connection failed: ' + err.stack);
          return;
        }
        console.log('Connected to database.');
      });

    // **Hit DB Query**
      connection.query("Query", function(err, rows, fields) {
           console.log(rows);
        });


      //**Close Connection**

connection.end(); ***// Missing this section will result in timeout***

    //**Send API Response**
      callback(null, {
              statusCode: '200',
              body: "Success",
              headers: {
                  'Content-Type': 'application/json',
              },
      });

    };

答案 8 :(得分:0)

connection.end()应该在回调之后:

工作代码:

    'use strict';
var mysql = require('mysql');

var connection = mysql.createConnection({
    host     : 'xxxxxx.amazonaws.com',
    user     : 'testuser',
    password : 'testPWD',
    port     : 3306,
    database: 'testDB',
    debug    : false        
});

module.exports.handler = (event, context, callback) => {
    // **Connection to database**      
    connection.connect(function(err) {
        if (err) {
            console.error('Database connection failed: ' + err.stack);
            context.fail();
            return;
        }
      else{ 
            console.log('Connected to database.');
        }
    });

    connection.query('show tables from testDB', function (error, results, fields) {
        if (error) {
            console.log("error: connection failed with db!");
            connection.destroy();
            throw error;
        } else {
            // connected!
            console.log("info: connection ok with db!");
            console.log(results);
            context.succeed("done");
            callback(error, results);
        }
    });

    //Send API Response
    callback(null, {
        statusCode: '200',
        body: 'succeed',
        headers: {
          'Content-Type': 'application/json',
        },
    });

    //Close Connection
    connection.end(); // Missing this section will result in timeout***

};