web-dev-qa-db-fra.com

Délai de connexion AWS Lambda RDS

J'essaie d'écrire une fonction Lambda à l'aide de Node.js qui se connecte à ma base de données RDS. La base de données fonctionne et est accessible à partir de mon environnement Elastic Beanstalk. Lorsque j'exécute la fonction, une erreur de délai d'attente est renvoyée.

J'ai essayé d'augmenter le délai d'attente jusqu'à 5 minutes avec exactement le même résultat.

La conclusion à laquelle j'en suis arrivé après quelques recherches est que c'est probablement un problème de sécurité mais que je n'ai pas trouvé la solution dans la documentation d'Amazon ou dans this answer (qui est le seul que j'ai pu trouver sur le sujet).

Voici les détails de sécurité:

  • Le RDS et le Lambda appartiennent au même groupe de sécurité.
  • Le RDS a toutes les règles de trafic entrant et sortant.
  • Lambda a une politique AmazonVPCFullAccess dans son rôle.

Mon code est:

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

};

Le résultat obtenu est:

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

Je tiens à remercier tous ceux qui ont aidé, le problème s'est avéré différent de ce que je pensais. La callback dans le code ne fonctionne pas pour une raison quelconque même si elle se trouve dans OWN DEFAULT SAMPLE d'Amazon.

Le code de travail ressemble à ceci:

'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

Bien que l'utilisation du contexte fonctionne, il vous suffit d'ajouter context.callbackWaitsForEmptyEventLoop = false; au gestionnaire, puis d'utiliser le rappel comme d'habitude, comme ceci:

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

La réponse est ici dans la documentation (cela m'a pris quelques heures pour trouver ceci): http://docs.aws.Amazon.com/lambda/latest/dg/nodejs-prog-model-using-old -runtime.html

Dans la section "Comparaison des méthodes de contexte et de rappel", une note "Important" explique tout. 

Au bas de la note, on peut lire:

Par conséquent, si vous souhaitez le même comportement que les méthodes de contexte, vous devez définir la propriété de l'objet de contexte, callbackWaitsForEmptyEventLoop, sur false.

En gros, le rappel se poursuit jusqu'à la fin de la boucle d'événement, contrairement au contexte qui termine la boucle d'événement. Par conséquent, si vous définissez callbackWaitsForEmptyEventLoop, le rappel fonctionne comme un contexte.

21
ambaum2

Le RDS et le Lambda appartiennent au même groupe de sécurité. 

C'est la clé. Par défaut, la communication au sein du même groupe de sécurité n'est pas autorisée. Et vous devez l’autoriser explicitement (E.x sg-xxxxx ALL TCP). Cela ne fonctionnera que si votre lambda tente d’accéder à la base de données par adresse IP privée. 

S'il essaie d'y accéder via une adresse IP publique, cela ne fonctionnera pas et vous devrez également percer les trous nécessaires. 

Cependant, il existe une meilleure approche:

  1. Créez un groupe de sécurité distinct pour votre lambda
  2. Autoriser le trafic entrant sur le port 3306 dans RDS sg pour lambdas sg.
3
Vor

Je partage mon expérience lors de la connexion à RDS.

Vous devez activer l'accès VPC pour le Lambda function, au cours duquel vous lui attribuerez un groupe de sécurité .

Ensuite, dans le groupe de sécurité attribué à l'instance RDS, vous activerez l'accès au groupe de sécurité affecté à la fonction Lambda.

Vous pouvez obtenir plus d'informations ici

2
abdulbarik

Lors de la configuration initiale de la base de données, un groupe de sécurité sera automatiquement créé. par défaut, l'adresse IP avec laquelle vous avez configuré la base de données. Lorsque vous exécutez lambda, cette règle bloque le trafic. Consultez les journaux de vos erreurs de base de données et confirmez qu’il refuse la connexion.

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

Vous devez créer une règle dans le groupe de sécurité pour autoriser le trafic lambda. Accédez à la console de votre instance RDS et cliquez sur le groupe de sécurité, sélectionnez Inbound. Là, vous verrez les règles. Appelez ensuite pour vous ouvrir au monde, recherchez les adresses IP AWS lambda ou créez un VPC. 

2
toonsend

connection.end () devrait être après le rappel:

code de travail:

    '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

Le problème ne provient pas du délai d'attente, mais de la façon dont vous fermez la connexion. Utilisez plutôt .destroy() si vous ne voulez pas attendre le rappel que OR l'utilise correctement lors de la fermeture de la connexion dans .end(function(err) { //Now call your callback });.

Voir ce fil de discussion pour une explication plus détaillée.

0
DR.

J'ai également fait face à un scénario de délai d'attente similaire. Le problème ne concernait pas connection.end() après connection.connect(). Connection.end() devrait être fait avant callback.

Code de travail:

  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