2015-07-26 12 views
21

Ich versuche, hochgeladene Datei in S3 zu verarbeiten. Seit getObject ist asynchrone Hauptfunktion beendet, bevor die Verarbeitung abgeschlossen ist, und AWS tötet Lambda in 3-4 Sekunden.Warten auf asynchrone Aktionen in AWS Lambda?

Noch schlimmer, die Verarbeitungsmethode hat auch asynchrone Operationen darin - es macht http Aufrufe.

Auf hohem Niveau, sieht mein Code wie:

exports.handler = function(event, context) { 
    // Get the object from the event and show its content type 
    var bucket = event.Records[0].s3.bucket.name; 
    var key = event.Records[0].s3.object.key; 
    var params = { 
     Bucket: bucket, 
     Key: key 
    }; 
    s3.getObject(params, function(err, data) { 
     if (err) { 
      ... 
     } else { 
      processFile(data.Body.toString(), 0); 
      console.log("ok"); 
     } 
    }); 
    //need to wait here till processFile is done 
}; 

processFile = function(content, start) { 
    ... build url to call 
    http.get(url, function(res) { 
    console.log("Got response: " + res.statusCode + "); 
    processFile(content, start + 1); 
    }); 
} 

ich herausfinden, dass es async in NodeJS ist, aber es ist nicht von amazon enthalten sind; Beide erfordern ('async') oder erfordern ('schlaf') verursacht Fehler.

Lambda-Timeout konfiguriert auf 60 Sekunden, aber es wird in 3-4 Sekunden beendet.

+0

Ich kann bestätigen, ähnliche Probleme mit AWS Lambda zu sehen, und die Timeout-Einstellungen, die nicht die logische Wirkung der Erhöhung der Ausführungsfenster ... Zunehmende * Speicherzuweisung nicht * scheinen um die verfügbare Ausführungszeit zu erhöhen, aber seltsame Effekte werden immer noch beobachtet. – ericpeters0n

+0

erinnerst du dich daran, wie du das gelöst hast? – Juvaly

Antwort

5

Ich denke, Ihre Lambda-Funktion sollte mit einem context.done() Aufruf enden. Zum Beispiel, versuchen Sie es auf diese Weise ergänzt:

s3.getObject(params, function(err, data) { 
    if (err) { 
     ... 
     context.done("Error: " + err.stack); 
    } else { 
     processFile(data.Body.toString(), 0); 
     console.log("ok"); 
     context.done(null, "success"); 
    } 
}); 
+0

Ich habe context.done im letzten Handler, aber Lambda ist früher beendet, dass es dazu – st78

+2

Haben Sie context.done nach Ihrem s3.getObject Callback? Haben Sie versucht, context.done vom letzten Handler zu entfernen und es nur in den s3.getObject-Callback zu platzieren, so wie ich es oben gezeigt habe? Wahrscheinlich wird context.done außerhalb Ihres Callbacks aufgerufen, noch bevor der Rückruf von s3.getObject abgeschlossen ist. – rk2

7

async ist nicht inbegriffen, aber das bedeutet nicht, dass Sie es sich nicht hinzufügen können. Fügen Sie das Paket einfach lokal hinzu (npm install async) und fügen Sie den Ordner node_modules in Ihr ZIP ein, bevor Sie Ihre Lambda-Funktion hochladen.

Wenn Sie dev Abhängigkeiten separat behandeln möchten (z .: Test, aws-sdk Ihre Funktion lokal auszuführen, usw.), können Sie diese in Ihrem package.json unter devDependencies hinzuzufügen. Wenn Sie den Prozess des Entwickelns, Testens, Implementierens und der Promotion Ihres Codes automatisieren möchten, werden diese beiden Repos ebenfalls sehr praktisch sein.

Grunt routine to test, package and deploy your lambdas

Command line tool for running and deploying your lambda functions

5

Denken Sie an Lambda einfach als ein Programm, das Sie in einer bestimmten Zeit ausgeführt werden können. Die Tatsache, dass Sie asynchrone Anrufe tätigen, ist nett, da der (virtuelle) Prozessor möglicherweise diese Anrufe verschachteln kann. Wenn jedoch ein Teil Ihres Lambda-Programms länger dauert als die zugewiesene Zeit, wird die Ausführung fehlschlagen. Das ist der Kompromiss, den Sie eingehen und wie Amazon Geld verdient; durch den Verkauf von mehr Zeit oder Erinnerung.

Um das an Ihrem Ende zu beheben, können Sie den Speicher Ihrer Lambda-Funktion erhöhen. Dies erhöht nicht nur Ihren Arbeitsspeicher, sondern auch die Geschwindigkeit Ihres virtuellen Prozessors. Eine andere Sache, die Sie tun können, ist die Zeitüberschreitung zu erhöhen. AWS Lambda bietet jetzt bis zu 512 MB RAM und bis zu 5 Minuten Verarbeitungszeit. Ab diesem Post können sich diese Zahlen geändert haben, also überprüfen Sie here für die neuesten Grenzen. Um diese Einstellung zu ändern, gehen Sie zu Ihrer Funktion, dann zur Konfiguration und schließlich zum Fortgeschrittenen.

0

Sie können stattdessen einen synchronous Anruf tätigen; da Sie anscheinend Ihre Datei in der gleichen Lambda-Funktion verarbeiten.

Wenn Sie aus irgendeinem Grund einen Rückruf erhalten möchten; Sie können das tun, indem Sie entweder Lambda direkt aufrufen oder über etwas, das ein Lambda-Ereignis erzeugen würde. Beachten Sie, dass Lambda-Funktionen angeblich zustandslos sind; also sollten Sie alle benötigten Informationen weitergeben.

+3

Korrekt, ich habe einfach keinen Weg gefunden, s3.getObject synchron unter node.js zu starten und es in Java umzuschreiben. – st78

+0

Entschuldigung; Meine Vertrautheit mit node.js ist ziemlich begrenzt – Neil

3

Wenn Sie möchten, als auch require('async'); Pack oder require('sleep'); Pack verwenden, müssen Sie Ihre Funktion als zip Datei wie folgt laden:

Creating a Deployment Package (Node.js)

Zip alle Inhalte des Ordners, wie ich in diesem erklären auch Frage:

MQTT in AWS Lambda function for Alexa Javascript

Über die synchrone Verarbeitung, können Sie require('async'); normalerweise ist nur die async.series Funktion wie folgt zu verwenden:

async.series([ 
    function(callback) { 
     // to do the function 1 
     callback(); 
    }, 
    function(callback) { 
     // to do the function 2 
     callback(); 
    }, 
    function(callback) { 
     // to do the function 3 
     callback(); 
    } 
], function(err) { 
    // to do the function if any error happens... 

    if (err) { 
     //... 
    } 
    //.... 
}); 

diese Weise wird die lambda Funktion synchron arbeitet.

Ich hoffe Ihnen zu helfen.

8

Ich hatte genau das gleiche Problem auf meinen Händen.

Das Problem ist die Javascript-Ereignisschleife ist leer, so Lambda denkt, es ist getan.

So habe ich dieses Problem gelöst. Ich weiß, dass dies nicht ideal ist, und ich wünschte, es gäbe einen besseren Weg, aber ich wollte nicht a) Bibliotheken hinzufügen, b) Lambda-Aufrufe koordinieren oder c) zu einer anderen Sprache wechseln.

Am Ende des Tages funktioniert es.

exports.handler = (event, context, callback) => { 
 
     var response; 
 
     var callBackCount; 
 

 
     /* 
 
     Ensures the javascript event loop is never empty. 
 
     This is the key to keeping lambda from exiting early 
 
     */ 
 
     setInterval(function(){}, 1000); 
 

 
     /* 
 
     Tell lambda to stop when I issue the callback. 
 
     This is super important or the lambda funciton will always go until it hits the timeout limit you set. 
 
     */ 
 
     context.callbackWaitsForEmptyEventLoop = false; 
 
     
 
     //My way of determining when I'm done with all calls 
 
     callBackCount = 0; 
 
     
 
     //My info to return 
 
     response = ""; 
 
     
 
     //Various functions that make rest calls and wait for a response 
 
     asyncFunction1(); 
 
     asyncFunction2(); 
 
     asyncFunction3(); 
 

 
     //Same for asyncFunction 2 and 3 
 
     function asyncFunction1(){ 
 
      response += callBackResponseForThisMethod; 
 
     
 
      returnResponse(); 
 
     } 
 

 
     function returnReponse(){ 
 
      callBackCount++; 
 

 
      if(callBackCount == 3){ 
 
       //Lambda will stop after this as long as context.callbackWaitsForEmptyEventLoop was set to false 
 
       callback(null, JSON.stringify(response)); 
 
      } 
 
     } 
 

 
    };

http://docs.aws.amazon.com/lambda/latest/dg/nodejs-prog-model-context.html