2016-07-07 6 views
2

Ich bin neuer Anfänger in Serverless Framwork. Wenn Sie Best Practices in Serverless studieren. hereBest Practices in Serverless Framework

Ich habe eine Frage über "Initialisieren externer Dienste außerhalb Ihres Lambda-Codes". Wie wird es implementiert? Zum Beispiel: Im Folgenden Code in handler.js

const getOneUser = (event, callback) => { 
    let response = null; 
    // validate parameters 
    if (event.accountid && process.env.SERVERLESS_SURVEYTABLE) { 
    let docClient = new aws.DynamoDB.DocumentClient(); 
    let params = { 
     TableName: process.env.SERVERLESS_USERTABLE, 
     Key: { 
     accountid: event.accountid, 
     } 
    }; 
    docClient.get(params, function(err, data) { 
     if (err) { 
     // console.error("Unable to get an item with the request: ", JSON.stringify(params), " along with error: ", JSON.stringify(err)); 
     return callback(getDynamoDBError(err), null); 
     } else { 
     if (data.Item) { // got response 
      // compose response 
      response = { 
      accountid: data.Item.accountid, 
      username: data.Item.username, 
      email: data.Item.email, 
      role: data.Item.role, 
      }; 
      return callback(null, response); 
     } else { 
      // console.error("Unable to get an item with the request: ", JSON.stringify(params)); 
      return callback(new Error("404 Not Found: Unable to get an item with the request: " + JSON.stringify(params)), null); 
     } 
     } 
    }); 
    } 
    // incomplete parameters 
    else { 
    return callback(new Error("400 Bad Request: Missing parameters: " + JSON.stringify(event)), null); 
    } 
}; 

Die Frage ist, wie DynamoDB außerhalb meines Lambda-Code paraphieren.

Update 2:

Ist unten Code optimiert?

handler.js

let survey = require('./survey'); 
module.exports.handler = (event, context, callback) => { 
    return survey.getOneSurvey({ 
     accountid: event.accountid, 
     surveyid: event.surveyid 
    }, callback); 
}; 

survey.js

let docClient = new aws.DynamoDB.DocumentClient(); 
module.exports = (() => { 
    const getOneSurvey = (event, callback) {.... 
     docClient.get(params, function(err, data)... 
     .... 
    }; 

    return{ 
    getOneSurvey : getOneSurvey, 
    } 
})(); 
+0

* "Ist unterhalb Code optimiert?" * Ich würde Nein sagen, nicht nach dieser Regel. Jedes Mal, wenn "Handler" aufgerufen wird, "Umfrage".getOneSurvey() 'wird aufgerufen, und jedes Mal erstellen Sie einen neuen' aws.DynamoDB.DocumentClient'. Dies sollte nur dann einer Variablen mit dem entsprechenden Umfang zugewiesen werden, wenn der Code zum ersten Mal geladen wird, und nicht jedes Mal, wenn der Handler aufgerufen wird. –

+0

OK! Ich habe docClient außerhalb der module.exports platziert. Es lädt zunächst und erstellt nur einen docClient. Ist mein Denken richtig? – Jim

Antwort

6

Hier ist das Zitat in Frage:

initialisieren externe Dienste außerhalb des Lambda-Code

Wenn Sie Dienste (wie DynamoDB) verwenden, stellen Sie sicher, dass Sie außerhalb Ihres Lambda-Codes initialisieren. Beispiel: Modulinitialisierung (für Knoten) oder für einen statischen Konstruktor (für Java). Wenn Sie innerhalb der Lambda-Funktion eine Verbindung zu DDB herstellen, wird dieser Code bei jedem Aufruf ausgeführt.

Mit anderen Worten, in der gleichen Datei, aber außerhalb - vor - der tatsächlichen Handler-Code.

let docClient = new aws.DynamoDB... 
... 
const getOneUser = (event, callback) => { 
.... 
    docClient.get(params, ... 

Wenn der Container gestartet wird, wird der Code außerhalb des Handlers ausgeführt. Wenn nachfolgende Funktionsaufrufe den gleichen Container wiederverwenden, sparen Sie Ressourcen und Zeit, indem Sie die externen Dienste nicht erneut instanziieren. Container werden häufig wiederverwendet, aber jeder Container verarbeitet nur eine gleichzeitige Anforderung gleichzeitig und wie oft werden sie wiederverwendet und wie lange liegt außerhalb Ihrer Kontrolle ... Wenn Sie die Funktion nicht aktualisieren, werden in diesem Fall keine vorhandenen Container mehr vorhanden sein wiederverwendet, weil sie die alte Version der Funktion haben.

Ihr Code funktioniert wie beschrieben, ist jedoch nicht optimiert.

Der Vorbehalt mit diesem Ansatz, der in aktuellen Generation Node.js Lambda-Funktionen (Knoten 4.x/6.x) entsteht, ist, dass einige Objekte - vor allem diejenigen, die dauerhafte Verbindungen zu externen Diensten literal erstellen - verhindern die Event-Schleife wird leer (ein bekanntes Beispiel ist eine MySQL-Datenbankverbindung, die eine Live-TCP-Verbindung zum Server hält; im Gegensatz dazu ist eine DynamoDB- "Verbindung" tatsächlich verbindungslos, da ihr Transportprotokoll HTTPS ist). In diesem Fall müssen Sie entweder einen anderen Ansatz wählen oder allow lambda to not wait for an empty event loop bevor Sie den Container einfrieren, indem Sie context.callbackWaitsForEmptyEventLoop auf false setzen, bevor Sie den Callback aufrufen ... aber tun Sie dies nur bei Bedarf und nur, wenn Sie vollständig verstehen, was es bedeutet. Wenn du es standardmäßig einstellst, weil ein Typ im Internet gesagt hat, dass es eine gute Idee ist, wirst du später vielleicht mysteriöse Bugs bekommen.

+0

Vielen Dank für die perfekte Antwort! Ich habe meine Frage aktualisiert! – Jim

+0

Was ist mit Testen und Mocking? Ich benutze 'aws-sdk-mock' und dort finden Sie: _Der AWS-Service muss innerhalb der zu testenden Funktion initialisiert werden, damit die SDK-Methode mocked_ wird. Um dies zum Laufen zu bringen, musste ich 'var dynamoDb = AWS.DynamoDB();' in 'exports.handler = function (event, context) {' [Siehe ihr Beispiel 2] (https: // www .npmjs.com/package/aws-sdk-mock) – iaforek

+0

@iaforek * prima facie *, das scheint tatsächlich ein Problem zu sein, weil es nicht zu einem optimalen Design führt, wenn der Code so geschrieben wird. Klar (!?) Ist der Overhead des Initialisierens des Objekts bei jeder Ausführung der Handlerfunktion weniger effizient, als dies nur einmal für jeden Container zu tun. –