it-roy-ru.com

Тайм-аут соединения AWS Lambda RDS

Я пытаюсь написать функцию Lambda, используя Node.js, который подключается к моей базе данных RDS. База данных работает и доступна из моей среды Elastic Beanstalk. Когда я запускаю функцию, она возвращает ошибку тайм-аута.

Пытался увеличить время ожидания до 5 минут с точно таким же результатом.

После некоторых исследований я пришел к выводу, что это, вероятно, проблема безопасности, но не удалось найти решение в документации Amazon или в this answer (единственном, который я смог найти по этой теме).

Вот детали безопасности:

  • И RDS, и Lambda находятся в одной группе безопасности.
  • RDS имеет все правила входящего и исходящего трафика.
  • Лямбда имеет политику 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"
13
Sir Codesalot

Хочу поблагодарить всех, кто помог, проблема оказалась не такой, как я думал. 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');
    });

};
9
Sir Codesalot

Хотя использование контекста будет работать, вам просто нужно добавить 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 заставляет функцию обратного вызова работать как контекст.

21
ambaum2

И RDS, и Lambda находятся в одной группе безопасности. 

Это ключ. По умолчанию связь внутри одной группы безопасности запрещена. И вам нужно явно разрешить это (E.x sg-xxxxx ALL TCP). Это будет работать только в том случае, если ваша лямбда пытается получить доступ к БД по частному ip. 

Если он пытается получить доступ к нему по общедоступным IP-адресам, он не будет работать, и вам нужно будет также выполнить необходимые действия для этого. 

Однако есть лучший подход:

  1. Создайте отдельную группу безопасности для вашей лямбды
  2. Разрешить входящий трафик через порт 3306 в RDS sg для lambdas sg.
3
Vor

Я делюсь своим опытом при подключении RDS.

Вам необходимо включить доступ VPC для Lambda function, во время которого вы назначите ему Security Group .

Затем в группе безопасности, назначенной экземпляру RDS, вы включите доступ для группы безопасности, назначенной функции Lambda.

Вы можете получить больше информации здесь

2
abdulbarik

При первоначальной настройке БД она автоматически создает группу безопасности. по умолчанию используется IP-адрес, с которым вы устанавливаете БД. При запуске из лямбды это правило блокирует трафик. Проверьте ваши журналы ошибок БД, и вы можете подтвердить, что он отказывается от соединения.

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

Вам нужно создать правило в группе безопасности, чтобы разрешить лямбда-трафик. Перейдите в консоль вашего экземпляра RDS и нажмите на группу безопасности, выберите входящий. Там вы увидите правила. Затем позвоните, чтобы открыть миру, найти лямбда-адреса AWS или создать VPC. 

2
toonsend

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

};
0
xiyulangzi

Проблема не в тайм-ауте, а в том, как вы закрываете соединение. Вместо этого используйте .destroy(), если вы не хотите ждать обратного вызова, когда OR правильно использует обратный вызов при закрытии соединения в .end(function(err) { //Now call your callback });

Смотрите эту ветку для более глубокого объяснения.

0
DR.

Я также столкнулся с подобным сценарием тайм-аута. Проблема не выполнялась 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',
              },
      });

    };
0
user2735676