Reputation: 1691
I'm trying to use AWS lambda to test a few API calls using axios
, however I'm having some trouble. Every post I came across said the best way to handle promises in Lambda was to use async/await
rather than .then
, so I made the switch. When I run the program using node
it works perfectly, but when I invoke the Lambda locally, it seems like everything after the axios
call is being skipped. When I invoke the Lambda locally without await
, the calls after it run fine, but then I'm forced to use .then
which the Lambda doesn't wait for anyway. I've increased the Lambda timeout to 900
, and I've run sam build
before sam invoke local
every time.
function checkServers() {
console.log("Inside checkServer");
console.log("Before apis to test");
// apisToTest has length of 2
apisToTest.forEach(async (apiToTest) => {
console.log("Api to test");
let res = await axios(apiToTest)
console.log("x"); // This gets skipped
console.log(res); // This gets skipped
})
console.log("After api to test")
}
exports.lambdaHandler = async (event, context) => {
console.log("Inside lambda handler");
checkServers();
console.log("After lambda handler");
};
// Used to test app using node command
checkServers()
This yields the following output:
INFO Inside lambda handler
INFO Inside checkServer
INFO Before apis to test
INFO Api to test
INFO Api to test
INFO After api to test
INFO After lambda handler
Upvotes: 8
Views: 6735
Reputation: 420
Similar to what saart is saying you could try the below code and see if it works:
async function checkServers() {
const promises = apisToTest.map((apiToTest) => axios(apiToTest))
const resolvedPromises = await Promise.all(promises);
return resolvedPromises;
}
exports.lambdaHandler = async (event, context) => {
try {
const result = await checkServers();
console.log(result);
} catch (error) {
console.log(error)
}
};
// Used to test app using node command
checkServers();
Upvotes: 0
Reputation: 1691
Thanks for all of your replies, unfortunately those weren't the ideal solutions for my use case, though they were very helpful in me coming up with the solution.
async function checkServers() {
let emailBody = "";
let callResult = "";
let completedCalls = 0;
let promises = [];
for (const apiToTest of apisToTest) {
await axios(apiToTest).then((res) => {
// Do something
}).catch((r) => {
// Handle error
})
}
}
exports.lambdaHandler = async (event, context) => {
context.callbackWaitsForEmptyEventLoop = true;
await checkServers();
};
To summarize, I replaced the forEach
call to a for...of
call, changed the checkServers
to async
, and combined await
with .then()
and .catch
to handle the Promise
result. I was unaware that both can be used to do so in tandem. Hope this helps anyone that had an issue similar to the one I had.
Upvotes: 1
Reputation: 402
you got two options:
callbackWaitsForEmptyEventLoop
to true - and then AWS will wait until the eventloop is emptycheckServers
. Consider using await Promise.all([...])
to wait for all your promises to finish.Note: If you will run the lambda again, the events from the previous invocations may "leak" to the next invocation. You can learn about it here: https://lumigo.io/blog/node-js-lambda-execution-leaks-a-practical-guide/
Disclosure: I work in the company that published this blog post
Upvotes: 0