node.js AWS Lambda RDS 连接超时

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/42605093/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 18:03:21  来源:igfitidea点击:

AWS Lambda RDS connection timeout

node.jsamazon-web-servicesaws-lambdards

提问by Sir Codesalot

I'm trying to write a Lambda function using Node.js which connects to my RDS database. The database is working and accessible from my Elastic Beanstalk environment. When I run the function, it returns a timeout error.

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

Tried to increase the timeout up to 5 minutes with the exact same result.

试图将超时增加到 5 分钟,结果完全相同。

The conclusion I came to after some research is that it's probably a security issue but couldn't find the solution in Amazon's documentation or in thisanswer (which is the only one I could find on the topic).

经过一番研究,我得出的结论是,这可能是一个安全问题,但在亚马逊的文档或答案中找不到解决方案(这是我在该主题上唯一能找到的)。

Here are the security details:

以下是安全细节:

  • Both the RDS and the Lambda are in the same security group.
  • The RDS has All traffic inbound and outbound rules.
  • The Lambda has AmazonVPCFullAccess policy in it's role.
  • RDS 和 Lambda 都在同一个安全组中。
  • RDS 具有所有流量入站和出站规则。
  • Lambda 在其角色中具有 AmazonVPCFullAccess 策略。

My code is:

我的代码是:

'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');
    });

};

The result I'm getting is:

我得到的结果是:

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

采纳答案by Sir Codesalot

I want to thank everyone who helped, the problem turned out to be different than I thought. The callbackin the code doesn't work for some reason even though it's in AMAZON'S OWN DEFAULT SAMPLE.

我要感谢所有帮助过的人,问题结果与我想象的不同。该callback代码不会因为即使是在亚马逊自己的默认采样某些原因。

The working code looks like this:

工作代码如下所示:

'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');
    });

};

回答by ambaum2

While using context will work, you just need to add context.callbackWaitsForEmptyEventLoop = false;to the handler and then use callback as normal like this:

虽然使用上下文会起作用,但您只需要添加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');
  });
};

The answer is here in the docs (took me a few hours to find this): http://docs.aws.amazon.com/lambda/latest/dg/nodejs-prog-model-using-old-runtime.html

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

In the section "Comparing the Context and Callback Methods" it has an "Important" note that explains things.

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

At the bottom of the note it reads:

在笔记的底部,它写道:

Therefore, if you want the same behavior as the context methods, you must set the context object property, callbackWaitsForEmptyEventLoop, to false.

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

Basically, callback continues to the end of the event loop as opposed to context which ends the event loop. So setting callbackWaitsForEmptyEventLoop makes callback work like context.

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

回答by Vor

Both the RDS and the Lambda are in the same security group.

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

That's the key. By default communication within the same security group is not allowed. And you need to explicitly allow it (E.x sg-xxxxx ALL TCP ). This wll only work if your lambda tries to access db by private ip.

这就是关键。默认情况下,不允许在同一安全组内进行通信。并且您需要明确允许它(例如 sg-xxxxx ALL TCP)。这仅在您的 lambda 尝试通过私有 ip 访问 db 时才有效。

If it tries to access it by public IP that it will not work and you need to punch necessary wholes for that as well.

如果它试图通过公共 IP 访问它,它将无法正常工作,您还需要为此进行必要的修改。

However there is better approach:

但是有更好的方法:

  1. Create separate separate security group for your lambda
  2. Allow inbound traffic on port 3306in RDS sg for lambdas sg.
  1. 为您的 lambda 创建单独的安全组
  2. 允许3306RDS sg 中端口上的入站流量用于 lambdas sg。

回答by abdulbarik

I am sharing my experience while connecting RDS.

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

You need to enable VPCaccess for the Lambda function, during which you will assign it a Security Group.

您需要启用VPC访问权限Lambda function,在此期间您将为其分配一个安全组

Then, within the Security Group assigned to the RDS instance, you will enable access for the Security Group assigned to the Lambda function.

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

You can get more info here

你可以在这里获得更多信息

回答by toonsend

When you originally setup the DB, it will automatically create a security group. defaulting to the IP that you set the DB up with. When you run from lambda this rule blocks traffic. Check out your db error logs and you can confirm it is refusing the connection.

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

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

You need to create a rule in the security group to allow lambda traffic. Go to your RDS instance console and click on the security group, select inbound. There you will see the rules. Then make the call to open up to the world, find the AWS lambda IPs or create a VPC.

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

回答by user2735676

I have also faced similar timeout scenario. Issue was not doing connection.end()after connection.connect(). Connection.end()should be done before callback.

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

Working Code:

工作代码:

  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',
              },
      });

    };

回答by xiyulangzi

the connection.end() should be after callback:

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

so working code:

所以工作代码:

    '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***

};

回答by DR.

The problem does not originate from the timeout, but from the way you close the connection. Use .destroy()instead if you do not want to wait for the callback that OR use the callback correctly when closing the connection in .end(function(err) { //Now call your callback });

问题不是源于超时,而是源于您关闭连接的方式。使用.destroy()替代,如果你不想等待回调或关闭在连接时正确使用回调.end(function(err) { //Now call your callback });

See this threadfor a more in depth explanation.

有关更深入的解释,请参阅此线程