tutorial succeed nodejs node modules exports example error create context aws node.js aws-lambda

node.js - succeed - exports.handler nodejs



¿Cómo esperar acciones asíncronas dentro de AWS Lambda? (7)

Estoy tratando de procesar el archivo cargado en S3. Como getObject es asíncrono, la función principal finaliza antes de que se complete el procesamiento, y AWS mata a lambda en 3-4 segundos.

Peor aún, el método de procesamiento también tiene operaciones asíncronas: realiza llamadas http.

En alto nivel, mi código se ve como:

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

Descubrí que hay async en nodejs pero no está incluido en Amazon; Ambos requieren (''async'') o requieren (''sleep) causan errores.

Tiempo de espera Lambda configurado a 60 segundos, pero sale en 3-4 segundos.


Creo que su función lambda debería terminar con una llamada context.done () . Por ejemplo, intente agregarlo de esta manera:

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


Es posible que desee hacer una llamada synchronous lugar; ya que parece estar procesando su archivo en la misma función lambda.

Si por alguna razón desea obtener una devolución de llamada; puede hacerlo invocando directamente a lambda o mediante algo que produzca un evento lambda. Tenga en cuenta que las funciones lambda se supone que son sin estado; por lo que debe pasar toda la información necesaria.


La vida de un desarrollador cambia constantemente y ahora tenemos NodeJS 8 en lambda. Para quien mira esto ahora echa un vistazo:

Comparación de Lambda node 8.10 vs node 6.10: https://aws.amazon.com/blogs/compute/node-js-8-10-runtime-now-available-in-aws-lambda/

Conceptos básicos de JS async: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function

Incluso más ejemplos de aws sdk: https://docs.aws.amazon.com/sdk-for-javascript/v2/developer-guide/using-promises.html

Los detalles sobre wtf el método .promise () se encuentran en el primer enlace: https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/Request.html#promise-property

Aquí está mi ejemplo básico (intente pegar en su propia lambda):

exports.handler = async (event) => { function wait(){ return new Promise((resolve, reject) => { setTimeout(() => resolve("hello"), 2000) }); } console.log(await wait()); console.log(await wait()); console.log(await wait()); console.log(await wait()); console.log(await wait()); console.log(await wait()); return ''exiting'' };

Los rendimientos anteriores:

Como puedes ver esperó 12 segundos sin matar mi función :)

PARA HACER más de una cosa por espera, use la sintaxis de Promise.all ([]) de esta manera:

exports.handler = async (event) => { var uploadPromises = []; folder.files.forEach(file => { uploadPromises.push( s3.putObject({ Bucket: "mybucket", Key: file.name, Body: file.data }).promise()); }); await Promise.all(uploadPromises); return ''exiting'' };

Respuesta Orignal Abajo

Tenía exactamente el mismo problema en mis manos.

El problema es que el bucle de eventos de javascript está vacío, por lo que Lambda cree que está hecho.

Así es como resolví este problema. Me doy cuenta de que esto no es lo ideal, y me gustaría que hubiera una mejor manera, pero no quería a) agregar bibliotecas, b) coordinar invocaciones lambda, o c) cambiar a otro idioma.

Al final del día funciona.

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


Piense en Lambda simplemente como un programa que puede ejecutar en una cierta cantidad de tiempo. El hecho de que realice llamadas asíncronas es agradable ya que el procesador (virtual) posiblemente puede intercalar esas llamadas. Sin embargo, si alguna parte de su programa Lambda tarda más en completarse que el tiempo asignado, bueno, la ejecución fallará. Ese es el compromiso que haces y es cómo Amazon gana dinero; Vendiéndote más tiempo o memoria.

Para solucionarlo, puede aumentar la memoria asignada a su función Lambda. Esto no solo aumenta su RAM sino también la velocidad de su procesador virtual. Otra cosa que puedes hacer es aumentar el tiempo de espera. AWS Lambda ahora le permite hasta 512 MB de RAM y hasta 5 minutos de tiempo de procesamiento. A partir de esta publicación, es posible que esos números hayan cambiado, así que consulte los últimos límites. Para cambiar esta configuración, vaya a su función, luego a la configuración y finalmente avance.


Si desea utilizar require(''async''); empacar o require(''sleep''); también necesita cargar su función como un archivo zip como este:

Creación de un paquete de implementación (Node.js)

Zip todo el contenido de la carpeta como explico en esta pregunta también:

MQTT en la función AWS Lambda para Alexa Javascript

Sobre el procesamiento síncrono, puede usar require(''async''); Normalmente, es solo para usar la función async.series como esta:

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

De esta manera la función lambda funcionará de forma síncrona.

Espero te ayude


Usando async / await

let AWS = require(''aws-sdk''); let lambda = new AWS.Lambda(); let data; exports.handler = async (event) => { try { data = await lambda.getAccountSettings().promise(); } catch (err) { console.log(err); return err; } return data; };


async no está incluido, pero eso no significa que no pueda agregarlo usted mismo. Simplemente agregue el paquete localmente ( npm install async ) e incluya la carpeta node_modules en su ZIP antes de cargar su función Lambda.

Si desea manejar las dependencias de desarrollo por separado (por ejemplo: prueba, aws-sdk para ejecutar su función localmente, etc.), puede agregarlas bajo devDependencies en su package.json . Además, si desea automatizar el proceso de desarrollo, prueba, implementación y promoción de su código, estos dos repositorios resultarán muy útiles.

Rutina de rutina para probar, empaquetar y desplegar tus lambdas

Herramienta de línea de comandos para ejecutar y desplegar sus funciones lambda