Home:ALL Converter>AWS Lambda RDS connection timeout

AWS Lambda RDS connection timeout

Ask Time:2017-03-05T14:07:36         Author:Sir Codesalot

Json Formatter

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.

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

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 this answer (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.

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"

Author:Sir Codesalot,eproduced under the CC 4.0 BY-SA copyright license with a link to the original source and this disclaimer.
Link to original article:https://stackoverflow.com/questions/42605093/aws-lambda-rds-connection-timeout
abdulbarik :

I am sharing my experience while connecting RDS.\n\n\n You need to enable VPC access for the Lambda function, during which you will assign it a Security Group.\n\n\nThen, within the Security Group assigned to the RDS instance, you will enable access for the Security Group assigned to the Lambda function.\n\nYou can get more info here",
2017-03-05T07:15:20
user2735676 :

I have also faced similar timeout scenario. Issue was not doing connection.end() after connection.connect(). Connection.end() should be done before callback.\n\nWorking Code:\n\n var mysql = require('mysql');\n\n var connection = mysql.createConnection({\n host : 'host_name',\n user : 'root',\n password : 'password'\n });\n\n\n module.exports.handler = (event, context, callback) => {\n\n// **Connection to database** \nconnection.connect(function(err) {\n if (err) {\n console.error('Database connection failed: ' + err.stack);\n return;\n }\n console.log('Connected to database.');\n });\n\n // **Hit DB Query**\n connection.query(\"Query\", function(err, rows, fields) {\n console.log(rows);\n });\n\n\n //**Close Connection**\n\nconnection.end(); ***// Missing this section will result in timeout***\n\n //**Send API Response**\n callback(null, {\n statusCode: '200',\n body: \"Success\",\n headers: {\n 'Content-Type': 'application/json',\n },\n });\n\n };\n",
2017-12-24T07:04:04
user1705352 :

It took me around 2 days to figure out the exact issue. In my case, both RDS and Lambda function was in Same VPC, Subnet and security group and added the Required Roles but still was getting Socket timeout exception. I was able to solve the issue by changing inbound and outbound rule by following the below link -\nhttps://aws.amazon.com/premiumsupport/knowledge-center/connect-lambda-to-an-rds-instance/",
2021-04-28T05:36:44
Adrian Smith :

Many thanks to @Sir Codesalot for finding the solution to this problem. The code below shows an example of how to run a SQL query after connection. I have also removed the aws-sdk which drops the zipped file size down from 10MB to 300k.\n'use strict';\n\nvar mysql = require('mysql');\n\nexports.handler = (event, context) => {\n\nvar connection = mysql.createConnection({\n host: 'abc.eu-west-2.rds.amazonaws.com',\n user: 'dbuser',\n password: '1234',\n port: 3306,\n database: 'db1234',\n debug: false\n});\n\nconnection.connect(function (err) {\n\n if (err) context.fail()\n\n let sql = "SELECT `id`,`tel`,`email` FROM `campaigns` WHERE `campaign` LIKE 'fish'"\n\n connection.query(sql, function (err, result) {\n if (err) throw err;\n context.succeed(JSON.stringify(result));\n });\n});\n\n};",
2022-07-08T10:40:05
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 });\n\nSee this thread for a more in depth explanation.",
2017-06-06T07:18:32
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:\n\nexports.handler = (event, context) => {\n context.callbackWaitsForEmptyEventLoop = false; \n var connection = mysql.createConnection({\n //connection info\n });\n connection.connect(function(err) {\n if (err) callback(err); \n else callback(null, 'Success');\n });\n};\n\n\nThe answer is here in the docs (took me a few hours to find this):\nhttp://docs.aws.amazon.com/lambda/latest/dg/nodejs-prog-model-using-old-runtime.html\n\nIn the section \"Comparing the Context and Callback Methods\" it has an \"Important\" note that explains things. \n\nAt the bottom of the note it reads:\n\n\n Therefore, if you want the same behavior as the context methods, you must set the context object property, callbackWaitsForEmptyEventLoop, to false.\n\n\nBasically, 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.",
2017-07-17T15:07:06
Vor :

\n\n\nBoth the RDS and the Lambda are in the same security group.\n\n\n\nThat'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.\nIf it tries to access it by public IP that it will not work and you need to punch necessary wholes for that as well.\nHowever there is better approach:\n\nCreate separate security group for your lambda\nAllow inbound traffic on port 3306 in RDS sg for lambdas sg.\n",
2017-03-05T17:49:41
Sir Codesalot :

I want to thank everyone who helped, the problem turned out to be different than I thought. The callback in the code doesn't work for some reason even though it's in AMAZON'S OWN DEFAULT SAMPLE.\n\nThe working code looks like this:\n\n'use strict';\nconsole.log(\"Loading getContacts function\");\n\nvar AWS = require('aws-sdk');\nvar mysql = require('mysql');\n\nexports.handler = (event, context) => {\n\n var connection = mysql.createConnection({\n host : '...',\n user : '...',\n password : '...',\n port : 3306,\n database: 'ebdb',\n debug : false\n });\n\n connection.connect(function(err) {\n if (err) context.fail();\n else context.succeed('Success');\n });\n\n};\n",
2017-03-06T06:39:31
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.\n\n***** could not be resolved: Name or service not known\n\n\nYou 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. ",
2018-01-31T10:48:20
yy