2015-07-26 20 views
21

Sto cercando di elaborare il file caricato in S3. Dal getObject la funzione principale asincrona termina prima che l'elaborazione sia terminata e AWS uccide lambda in 3-4 secondi.Come attendere le azioni asincrone all'interno di AWS Lambda?

Ancora peggio, il metodo di elaborazione ha anche operazioni asincrone in esso - effettua chiamate http.

Su di alto livello, il mio codice è simile:

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

scopro che c'è asincrono in nodejs, ma non è incluso da Amazon; Entrambi richiedono ('async') o richiedono ('sleep) causa errori.

Timeout lambda configurato su 60 secondi, ma esce in 3-4 secondi.

+0

Posso confermare visto problemi simili con AWS lambda, e le impostazioni di timeout non avere l'effetto logica di finestra di esecuzione aumentando ... Aumentare l'allocazione di memoria * non * sembrano per aumentare il tempo di esecuzione disponibile, ma si osservano ancora strani effetti. – ericpeters0n

+0

ti ricordi come hai risolto questo? – Juvaly

risposta

5

Penso che la funzione lambda dovrebbe terminare con una chiamata context.done(). Per esempio, prova ad aggiungere in questo modo:

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

Ho context.done nell'ultimo handler, ma lambda è terminato prima che arrivi ad esso – st78

+2

Hai contesto.done dopo il tuo callback s3.getObject? Hai provato a rimuovere context.done dall'ultimo gestore e lo hai inserito solo nel callback s3.getObject, come nel modo in cui ho mostrato sopra? Probabilmente contesto.done al di fuori della richiamata viene chiamato anche prima che il callback s3.getObject sia completato. – rk2

7

async non è incluso, ma questo non significa che non è possibile aggiungere voi stessi. È sufficiente aggiungere il pacchetto localmente (npm install async) e includere la cartella node_modules nel proprio ZIP prima di caricare la funzione Lambda.

Se si desidera gestire le dipendenze dev separatamente (ad es .: prova, aws-sdk per eseguire la funzione a livello locale, ecc), è possibile aggiungerli sotto devDependencies nel vostro package.json. Inoltre, se vuoi automatizzare il processo di sviluppo, test, distribuzione e promozione del tuo codice, questi due repository risulteranno molto utili.

Grunt routine to test, package and deploy your lambdas

Command line tool for running and deploying your lambda functions

5

Pensate Lambda semplicemente come un programma che è possibile eseguire in un determinato lasso di tempo. Il fatto che si effettuino chiamate asincrone è piacevole poiché il processore (virtuale) può eventualmente intercalare quelle chiamate. Tuttavia, se una parte del tuo programma Lambda impiega più tempo per completare il tempo assegnato, beh, l'esecuzione fallirà. Questo è il compromesso che fai ed è il modo in cui Amazon guadagna denaro; vendendoti più tempo o memoria.

Per risolvere il problema è possibile aumentare la memoria assegnata alla funzione Lambda. Questo non solo aumenta la tua RAM ma anche la velocità del tuo processore virtuale. Un'altra cosa che puoi fare è aumentare il timeout. AWS Lambda ora ti consente fino a 512 MB di RAM e fino a 5 minuti di tempo di elaborazione. A partire da questo post questi numeri potrebbero essere cambiati, quindi controlla here per gli ultimi limiti. Per modificare questa impostazione, vai alla tua funzione, quindi alla configurazione e infine avanzata.

0

È possibile effettuare una chiamata synchronous; dal momento che sembra che tu stia elaborando il tuo file con la stessa funzione lambda.

Se per qualche motivo si desidera ottenere una richiamata; puoi farlo invocando direttamente lambda o qualcosa che potrebbe produrre un evento lambda. Si noti che le funzioni lambda dovrebbero essere apolidi; quindi dovresti passare tutte le informazioni necessarie.

+3

Corretto, non ho trovato un modo per fare s3.getObject sincronicamente sotto node.js e riscriverlo su java. – st78

+0

scusa; la mia familiarità con node.js è piuttosto limitata – Neil

3

Se si desidera utilizzare require('async'); pack o require('sleep'); pacchetto così è necessario caricare la vostra funzione come file zip come questo:

Creating a Deployment Package (Node.js)

Zip tutto il contenuto della cartella come spiego in questo domanda così:

MQTT in AWS Lambda function for Alexa Javascript

Circa l'elaborazione sincrona, è possibile utilizzare require('async'); normalmente, è solo quello di utilizzare la funzione async.series in questo modo:

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) { 
     //... 
    } 
    //.... 
}); 

In questo modo il lambda funzione lavora in modo sincrono.

Spero di aiutarti.

8

Ho avuto lo stesso identico problema sulle mie mani.

Il problema è che il ciclo di eventi javascript è vuoto, quindi Lambda pensa che sia fatto.

Ecco come ho risolto questo problema. Mi rendo conto che questo non è l'ideale, e mi piacerebbe che ci fosse un modo migliore, ma non volevo a) aggiungere librerie, b) coordinare invocazioni lambda, o c) passare a un'altra lingua.

Alla fine della giornata funziona.

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

Problemi correlati