2016-08-01 24 views
1

Ich begann mit AWS Lambda eine sehr einfache Aufgabe ausführen, die eine SQL-Abfrage zum Abrufen von Datensätzen aus einer RDS-Postgres-Datenbank und SQS-Nachricht Basis auf das Ergebnis ausführen.Warum AWS Lambda Ausführungszeit lang ist mit Pg-Versprechen

Da Amazon nur aws-sdk-Modul (mit Knoten 4.3-Engine) standardmäßig bereitstellt und wir diese SQL-Abfrage ausführen müssen, müssen wir ein benutzerdefiniertes Bereitstellungspaket erstellen, das pg-promise enthält. Hier ist der Code Ich verwende:

console.info('Loading the modules...'); 
var aws = require('aws-sdk'); 
var sqs = new aws.SQS(); 
var config = { 
    db: { 
    username: '[DB_USERNAME]', 
    password: '[DB_PASSWORD]', 
    host: '[DB_HOST]', 
    port: '[DB_PORT]', 
    database: '[DB_NAME]' 
    } 
}; 

var pgp = require('pg-promise')({}); 
var cn = `postgres://${config.db.username}:${config.db.password}@${config.db.host}:${config.db.port}/${config.db.database}`; 

if (!db) { 
    console.info('Connecting to the database...'); 
    var db = pgp(cn); 
} else { 
    console.info('Re-use database connection...'); 
} 

console.log('loading the lambda function...'); 
exports.handler = function(event, context, callback) { 

    var now = new Date(); 
    console.log('Current time: ' + now.toISOString()); 

    // Select auction that need to updated 
    var query = [ 
    'SELECT *', 
    'FROM "users"', 
    'WHERE "users"."registrationDate"<=${now}', 
    'AND "users"."status"=1', 
    ].join(' '); 

    console.info('Executing SQL query: ' + query); 
    db.many(query, { status: 2, now: now.toISOString() }).then(function(data) {  
    var ids = []; 
    data.forEach(function(auction) { 
     ids.push(auction.id); 
    }); 

    if (ids.length == 0) { 
     callback(null, 'No user to update'); 

    } else { 

     var sqsMessage = { 
     MessageBody: JSON.stringify({ action: 'USERS_UPDATE', data: ids}), /* required */ 
     QueueUrl: '[SQS_USER_QUEUE]', /* required */ 
     }; 

     console.log('Sending SQS Message...', sqsMessage); 
     sqs.sendMessage(sqsMessage, function(err, sqsResponse) { 

     console.info('SQS message sent!'); 
     if (err) { 
      callback(err); 
     } else { 
      callback(null, ids.length + ' users were affected. SQS Message created:' + sqsResponse.MessageId); 
     } 
     }); 
    } 

    }).catch(function(error) { 
    callback(error); 
    }); 

}; 

Wenn meine Lambda-Funktion zu testen, wenn man sich die WatchLogs sehen, die Funktion selbst dauerte etwa 500ms zu laufen, aber es sagt, dass es tatsächlich dauerte 30.502,48 ms (vgl Screenshots).

enter image description here enter image description here

So vermute ich es 30 Sekunden ist unter meiner 318KB Paket zu entpacken und die Ausführung starten? Das ist für mich nur ein Witz oder fehlt mir etwas? Ich habe versucht, die Zip-Datei hochzuladen und auch mein Paket in S3 hochzuladen, um zu prüfen, ob es schneller war, aber ich habe immer noch die gleiche Latenz.

bemerkte ich, dass die Python-Version nativ SQL Anfrage ohne Spezialverpackungen durchführen können ...

Alle unsere Anwendungen sind in Knoten geschrieben, damit ich wirklich nicht von ihm weg bewegen wollen, aber ich habe ein Es ist schwer zu verstehen, warum Amazon keine grundlegenden npm-Module für Datenbankinteraktionen bereitstellt.

Kommentare oder Hilfe sind willkommen. An dieser Stelle bin ich nicht sicher Lambda würde uns nützen, wenn es 30 Sekunden dauert, um ein Skript auszuführen, das jede Minute ausgelöst wird ...

Wer hat das gleiche Problem?


UPDATE: Dies ist, wie Sie die Verbindung schließen müssen, sobald Sie es nicht mehr benötigen (nochmals vielen Dank an Vitaly für seine Hilfe):

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

    [...] 

    db.many(query, { status: 2, now: now.toISOString() }).then(function(data) {  

    pgp.end(); // <-- This is important to close the connection directly after the request 

    [...] 
+0

Versuchen Sie, mehr Protokollierung hinzuzufügen, um festzustellen, woher die 30 Sekunden kommen, ob es die Abfrage selbst ist oder etwas, was Sie danach tun. Es gibt nicht genug Informationen in dem, was Sie gepostet haben, um genau zu bestimmen.Und AWS neigt dazu, die Laufzeitumgebung für jede Sprache zu machen, die den "Standard" der Sprache unterstützt (plus das AWS SDK). Python kann den SQL-Standard berücksichtigen, JavaScript dagegen nicht. –

+0

Wahrscheinlich relevant, um Erwartungen zu setzen: https://docs.aws.amazon.com/lambda/latest/dg/lambda-introduction-function.html#topic3 ​​ –

+0

Ich habe Protokolle am Anfang (erste Zeile "Verbindung mit der Datenbank")) und am ende (cf. cloudwatch screenshot) damit ich weiß, dass die Ausführungszeit von MY code ~ 500ms beträgt oder nimm. Es erklärt nicht die 30 anderen Sekunden, die berechnet werden. Wenn Sie die von Ihnen zur Verfügung gestellten Dokumente lesen, wird nicht erklärt, was genau in diesen 30 Sekunden passiert. Ist es an der Zeit zu entpacken? den Container erstellen? – maxwell2022

Antwort

3

Die Ausführungszeit sollte basierend auf der Länge der ausgeführten Vorgänge gemessen werden, im Gegensatz dazu, wie lange es dauert, bis die Anwendung beendet wird.

Es gibt viele Bibliotheken, die einen Verbindungspool in der einen oder anderen Form verwenden. Diese enden normalerweise nach einer konfigurierbaren Inaktivitätszeit.

Bei pg-promise, die wiederum node-postgres wie Inaktivitätszeit verwendet wird durch Parameter bestimmt poolIdleTimeout, die standardmäßig bis 30 Sekunden. Mit pg-promise können Sie über pgp.pg.defaults.poolIdleTimeout darauf zugreifen. Wenn Sie möchten, dass Ihr Prozess beendet wird, nachdem die letzte Abfrage ausgeführt wurde, müssen Sie den Verbindungspool herunterfahren, indem Sie pgp.end() aufrufen. Einzelheiten finden Sie in Kapitel Library de-initialization.

Es wird auch in den meisten der code examples gezeigt, da diese direkt nach der Fertigstellung verlassen müssen.