Как ждать асинхронных действий внутри AWS Lambda?
Я пытаюсь обработать загруженный файл в S3. Поскольку getObject заканчивается как основная задача, заканчивается до завершения обработки, а AWS убивает лямбда за 3-4 секунды.
Хуже того, метод обработки также имеет асинхронные операции в нем - он делает http-вызовы.
На высоком уровне мой код выглядит так:
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);
});
}
Я узнаю, что в nodejs существует async, но он не включен amazon; Оба требуют ( "async" ) или требуют ( "сон" ) вызывает ошибки.
Время ожидания Lambda настроено на 60 секунд, но оно выйдет через 3-4 секунды.
Ответы
Ответ 1
async
не входит, но это не значит, что вы не можете добавить его самостоятельно.
Просто добавьте пакет локально (npm install async
) и включите папку node_modules
в свой ZIP перед загрузкой функции лямбда.
Если вы хотите обрабатывать зависимости dev отдельно (например: test, aws-sdk
для выполнения вашей функции локально и т.д.), вы можете добавить их под devDependencies
в свой package.json
. Кроме того, если вы хотите автоматизировать процесс разработки, тестирования, развертывания и продвижения своего кода, эти два репозитория окажутся очень удобными.
Процедура Grunt для тестирования, упаковки и развертывания ваших lambdas
Инструмент командной строки для запуска и развертывания ваших лямбда-функций
Ответ 2
У меня была такая же проблема на моих руках.
Проблема в том, что цикл событий javascript пуст, поэтому Lambda думает, что это сделано.
Вот как я решил эту проблему. Я понимаю, что это не идеально, и я хочу, чтобы был лучший способ, но я не хотел: a) добавлять библиотеки, b) координировать лямбда-вызовы или c) переключиться на другой язык.
В конце дня он работает.
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));
}
}
};
Ответ 3
Я думаю, что ваша лямбда-функция должна завершиться вызовом context.done(). Например, попробуйте добавить его так:
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");
}
});
Ответ 4
Подумайте о Lambda просто как программу, которую вы можете запустить за определенное время. Тот факт, что вы выполняете асинхронные вызовы, хорош, поскольку (виртуальный) процессор может чередовать эти вызовы. Однако, если какая-либо часть вашей Lambda-программы занимает больше времени, чем время, выделенное, ну, выполнение не будет выполнено. Это компромисс, который вы делаете и как Amazon зарабатывает деньги; продавая вам больше времени или памяти.
Чтобы исправить это, вы можете увеличить память, которую выделяет функция лямбда. Это не только увеличивает оперативную память, но и скорость вашего виртуального процессора. Еще одна вещь, которую вы можете сделать, - увеличить тайм-аут. AWS Lambda теперь позволяет вам до 512 МБ оперативной памяти и до 5 минут обработки. На этом посту эти цифры, возможно, изменились, поэтому отметьте здесь для последних ограничений. Чтобы изменить этот параметр, перейдите к своей функции, затем конфигурации и, наконец, расширенной.
Ответ 5
Если вы хотите использовать пакет require('async');
pack или require('sleep');
, вам необходимо загрузить свою функцию в виде файла zip
, например:
Создание пакета развертывания (Node.js)
zip
все содержимое папки, как я объясню в этом вопросе:
MQTT в функции AWS Lambda для Alexa Javascript
Об синхронной обработке вы можете использовать require('async');
как правило, просто использовать функцию async.series
следующим образом:
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) {
//...
}
//....
});
Таким образом, функция lambda
будет работать синхронно.
Я надеюсь помочь вам.
Ответ 6
Вместо этого вы можете сделать вызов synchronous
; так как вы, кажется, обрабатываете свой файл в той же лямбда-функции.
Если по какой-либо причине вы хотите получить обратный вызов; вы можете сделать это путем прямого вызова лямбда или с помощью чего-то, что приведет к событию лямбда. Обратите внимание, что лямбда-функции предполагаются апатридами; поэтому вы должны передать всю необходимую информацию.