execution not waiting for promise result in AWS Lambda - node.js

I'm trying to use promises in AWS Lambda and am having some trouble. I'm using typescript/nodejs; see code below
export function handler(event: any, context: any, callback: Function){
testFunction().then(data => callback(null, "success from promise"));
callback(null, "success");
}
export function testFunction(){
return new Promise((resolve, reject) => {
setTimeout(() => resolve("data"), 5000);
});
}
When I run the code I'm getting the "success callback" instead of the "success from promise". Am I doing something wrong here?

You are actually calling the callback twice: once on the fourth line "success" and once after the promise resolves. I think that lambda will essentially ignore the second callback (which is actually first in your code).
You can merely remove the other call:
export function handler(event: any, context: any, callback: Function){
testFunction().then(data => callback(null, "success from promise"));
}
Note: the callback is only supported by Node 4.3. It is also optional. You only need to use it if you want to explicitly pass data back to the caller. Otherwise it will be called automatically once the event loop is empty which in this case will happen after the promise resolves.
You can also change the setting of context.callbackWaitsForEmptyEventLoop = false if you want the lambda function to end immediately when callback is called instead of waiting for the event loop to finish. Most likely you won't need to do this, though.

Related

How to use Async and await inside of a loop

I am using Firebase and Nodejs in order to calculate some values. There are 40+ JSON objects will be there in the variable 'data'. 'getOHLCofStock' function expects a value and it will return a promise. But what happens here is, that the console.log function gets executed without waiting for the promise to resolve. Therefore, I am getting 'undefined' in the console.
Please help me to make this function wait and console the real value.
const path = db.ref(now);
path.on('value', async(snapshot) => {
for (const property in data) {
await zerodha.getOHLCofStock(property).then(async ohlc => {
console.log(ohlc);
//ohlc is 'undefined', but in fact, its not undefined. The 'await'
is not working here.
I want 'getOHLCofStock' should wait until the value gets resolved and
then only the console.log should execute.
})
}
})

Lambda Nodejs - (node:1) UnhandledPromiseRejectionWarning: #<Object>

exports.handler = async (event, context, callback) => {
try {
const { headers, body } = event;
//This is where I forgot the "await" keyword
const input = ValidateInput(body); //Returns Promise
callback(null, true);
}catch(err){
console.log(err);
callback(null, false);
}
}
When calling a function that returns a promise and forgetting to create an await expression promise function call, and that function rejects the promise, Lambda logs this error in cloudwatch
(node:1) UnhandledPromiseRejectionWarning: #<Object>
The fix is simple, don't forget the await expression
const input = await ValidateInput(body); //Return Promise
The fix is simple, don't forget the await expression
const input = await ValidateInput(body); //Return Promise
As already mentioned, the solution is to ensure you await the promise:
const input = await ValidateInput(body);
But I thought I'd add a little context around why this occurs.
Since Promises can be stored in variables and chained at any point, there's no way for the library to know whether or not a Promise chain will have a .catch associated with it some time in the future. Many libraries therefore have a default behaviour of writing to the console if the rejected Promise has not been handled within a number of passes of the event loop; which is why you see this in the log.
You should generally take this warning as implying that you haven't awaited something you should have. As in reality, it's rare that you'd see it on purpose.
The AWS doc explicitly says you don't use callback with an async function.
The third argument, callback, is a function that you can call in
non-async functions to send a response. The callback function takes
two arguments: an Error and a response. The response object must be
compatible with JSON.stringify.
For async functions, you return a response, error, or promise to the
runtime instead of using callback.
So, you may want to fix that in your lambda function.
See here : https://docs.aws.amazon.com/lambda/latest/dg/nodejs-prog-model-handler.html#nodejs-prog-model-handler-callback

Writing async/await version of a callback

I'm trying to rewrite a callback as async/await but following code doesn't work and results in high CPU at the commented line.
const kurento = require('kurento-client')
function getKurentoClient (kmsUrl) {
return new Promise((resolve, reject) => {
kurento(kmsUrl, (error, kurentoClient) => {
if (error) {
return reject(error)
} else {
return resolve(kurentoClient) // never returns
}
})
})
}
async function test () {
let result = await getKurentoClient('ws://localhost:8888/kurento')
console.log('done')
}
test()
From the mozilla.org website:
The Promise.resolve(value) method returns a Promise object that is resolved with the given value. If the value is a thenable (i.e. has a "then" method), the returned promise will "follow" that thenable, adopting its eventual state; if the value was a promise, that object becomes the result of the call to Promise.resolve; otherwise the returned promise will be fulfilled with the value.
And from bluebird GitHub:
when promises resolve other promises or things with then(aka thenables, like _kurentoClient in this case) - they have to wait for it to call then itself.
As you have guessed, kurento clients have a then function (so is a thenable) so the Promise is trying to resolve it. Because of a bug (or not a bug. Honestly, I have not researched enough to determine that) it keeps resolving itself forever.
As far as I see, seems that this kurento commit tries to fix it, resolving to an "untheanble". I see that the commit is from 31 Oct 2016 but the latest release is from Sep 2016 so I think that the fixed version is not deployed.

Intern: Testing async unit tests with ES6 promises

I have some async functions that I need to test via Intern. Each uses ES6 promises.
In the Intern docs, it says that test functions that return a promise pass as soon as that promise is resolved. However, I not only care about whether the async function I am testing is resolved/rejected, I also want to check to make sure the resolved value is correct.
Example: I have my function:
function getSomething() {
return new Promise((resolve, reject) => {
// do some async stuff and resolve when done
setTimeout(function() {
resolve('the value');
}, 1000);
});
}
Then I have the test method:
tdd.test('getSomething', function() {
return new Promise((resolve, reject) => {
getSomething().then(function(value) {
// I want to resolve/reject the promise BASED ON the assertion -- if the assertion fails, I want to reject the promise; if it succeeds, I want to resolve it
assert.equal(value, 'the value', 'getSomething should return "the value".');
resolve();
});
});
}
I've noticed this doesn't work -- if the assertion fails in my test, the resolve() never gets called.
How would I be able to resolve/reject the promise conditioned upon the assertion? Should I wrap the assertion in a try/catch? I didn't see any documentation on the Intern docs about this (and most were using this.async() instead of ES6 promises).
What's happening in your code is that the assertion in the getSomething callback is throwing an exception, and that's preventing resolve from being called. The getSomething promise will be rejected, but since you're not returning it in the wrapper promise's initializer, the wrapper promise is never resolved or rejected.
There is no need to wrap the promise returned by getSomething in a new promise. Just return it directly.

How to not run a Promise before I ask to

I thought I had it all figured out regarding Promise, but this one actually throws me out of bed. When creating a new Promise with a executor taking two arguments, why is this method running before I either take then() or catch() at that promise
Running node 6.2.2.
import assert = require('assert');
describe("When working with promises", () => {
let ar = [1, 2, 3, 4, 5, 6];
beforeEach(() => {
})
it("should be perfectly fine but isn't when mapping to promises", (done) => {
ar.map(num => {
return new Promise((resolve, reject) => {
done(new Error('Why on earth is ' + num + ' called'));
})
})
done();
})
it("should be perfectly fine when mapping to methods", (done) => {
ar.map(num => {
return (resolve, reject) => {
done(new Error(num + ' is not called ever'));
}
})
done();
})
});
First test fails, and second test is successful.
If you check the documentation for Promise, you will find that the function that is given to the constructor is run immediately. It is supposed to kick off the asynchronous calculation and install the two callbacks there (so that resolve and reject are not invoked just now, but whenever that calculation completes or fails).
The Promise function is not the asynchronous calculation, it just wraps that calculation and the two callbacks you need to keep track of it together into a nice package (and returns immediately after this setup is done).
Your second example creates an anonymous function for each number, but does not invoke any of them.
why is this method running before I either take then() or catch() at that promise
The Promise does not care if you install any handlers/chains. The calculation will have been started (or not) no matter if anyone is watching it or not.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise:
[...] The executor function is executed immediately by the Promise implementation, passing resolve and reject functions [...].
That's the way, the Promise implementation works. You can also create a new promise and attach chained then() or catch() handlers later when the promise already succeeded or failed.
const p = new Promise(someExecutor);
// do some other things
p.then(someHandler);
// do some other things
p.catch(someOtherHandler);
If you do not want the executor to execute, yet, then don't pass it to the Promise constructur, yet.
To achieve the same behavior you have to wrap promises in a factory. You can use a lambda functions for that.
it("should be perfectly fine but isn't when mapping to promises", (done) => {
ar.map(num => {
return () => new Promise((resolve, reject) => {
done(new Error('Why on earth is ' + num + ' called'));
})
})
done();
})
So you have stateless factories to call later without creating promises (that run immediately) during map.
It permits you to compose and join Promises for later batch execution using Promise.all, Promise.race, or custom chaining.
If you want something to run only (i.e. not before) a "then()" handler is attached, then you can use plain then-ables ( https://promisesaplus.com/ )
var runLater = {
then: function(resolve, reject) {
var p = new Promise (...); // Creating a promise is optional
resolve(p); // you can return a plain value
}
}
Note this is not a Promise, so it does not have a "catch" method.
But it can be given to any function expecting a promise:
`Promise.all([runLater])
return as result from a then handled .then(function() { return runLater; })
Promise.resolve(runLater) => Now it is a promise with then/catch
Any of those will call the runLater.then method.

Resources