Stripe promise pending even though it's async/await - node.js

I have a separate file created to facilitate stripe-based functions called stripe.js.
In this file I want to create a function that retrieves session object, so I initialize stripe with my test key and create function that I export as so:
const stripe = require('stripe')('my_stripe_key_here');
export async function obtainSession(sid) {
return await stripe.checkout.sessions.retrieve(sid);
}
Now in the App.vue I first import the function and try to use it:
import { obtainSession } from "./stripe/stripe";
let session = obtainSession(this.session_id)
.then(session=> {
return session
});
console.log(session)
And all I get is a pending promise in the console (Promise < pending >)
I've tried for a few days and tested different approaches from stackoverflow and elsewhere but I cannot seem to get this promise resolved. I am using a valid and existing session ID with no result.
Can anybody tell me what's the problem? Thanks!

let session = obtainSession(this.session_id)
.then(session=> {
return session
});
Doing this doesn’t mean this will return after the then- it will return immediately with the Promise returned by obtainSession. The continuation will also run once the promise resolves, but that return is basically meaningless in this flow.
You will have to await this call. Or if you log inside the then you’ll see the result.
You could consider retrieving this and awaiting inside mounted or similar, or have the code set session as a module variable. But in all cases this is going to be something that returns a promise you have to wait for outside of tHat assignment.

Related

NestJS async await requirement

I am trying out NestJS for the first time.
The question is simple, when I DO NOT use async await in my controller, I am able to return the data without await as async/await is used in the repository class methods
#Get('/:id')
getMessage(#Param('id') id: string) {
const messageId = id;
// works just fine 👇
const message = this.messagesService.findOne(messageId);
return message;
}
But when I make use of NotFoundException from NEST to make sure if I found the data I am supposed to return, I am forced to use async/await because without it, it considers the message to be always there. Which I am assuming is a Promise.
#Get('/:id')
async getMessage(#Param('id') id: string) {
const messageId = id;
// 👇 await
const message = await this.messagesService.findOne(messageId);
if (!message) {
throw new NotFoundException('Message with ID not found');
}
return message;
}
And if I do not use await, it does not throw an exception.
The question is, why/how does it work in the first example without the use of await
The await keyword returns a Promise. Therefore if you return a Promise you have satisfied the contract of returning a Promise.
I presume that Nest.js repository methods need to return a Promise. You have two choices. Either use the async keyword or return a Promise. In the first example you have returned a Promise so that is why it works.
Note that you don't need to use async if you don't want to. You can always go old school. This is what your first example would be like with the logic to check the message:
#Get('/:id')
getMessage(#Param('id') id: string) {
const messageId = id;
// works just fine 👇
const promise = this.messagesService.findOne(messageId).then((message) => {
if (!message) {
throw new NotFoundException('Message with ID not found');
}
else {
return message;
}
});
return promise;
}
We know that in JS, program runs synchronously and findOne is a webAPI provided by the browser. As it is a webapi it will first send the line
const message = this.messagesService.findOne(messageId);
to the api and will return that function again to stack once all the data is received.
(Assuming you know how the event loop and api works in JS)
In the first function you are not checking the variable message(if it is true or false) you are just returning the value so it will return only if the value is present.
But in second function you are checking the var message, if that line is written without the await it will directly go to the "if" statement even before the data is received from the api(findOne) at that time message var would still be undefined. So once you write await, stack will not go to the next line unless the answer from api is received, and at time your if statement will be checked perfectly.
The answer to your question is in the architecture of nestjs/node itself. If you return a promise (your first case) it resolve it and then returns the value. To get more clear idea about this check jiripospisil on 3 Aug 2018 on this issue.

Node.js .map function causing express server to return the response object early

My goal is to create an abstracted POST function for an express running on Node similar to Django's inbuilt REST methods. As a part of my abstracted POST function I'm checking the database (mongo) for valid foreign keys, duplicates, etc..., which is where we are in the process here. The function below is the one that actually makes the first calls to mongo to check that the incoming foreign keys actually exist in the tables/collections that they should exist in.
In short, the inbuilt response functionality inside the native .map function seems to be causing an early return from the called/subsidiary functions, and yet still continuing on inside the called/subsidiary functions after the early return happens.
Here is the code:
const db = require(`../../models`)
const findInDB_by_id = async params => {
console.log(`querying db`)
const records = await Promise.all(Object.keys(params).map(function(table){
return db[table].find({
_id: {
$in: params[table]._ids
}
})
}))
console.log('done querying the db')
// do stuff with records
return records
}
// call await findIndDB_by_id and do other stuff
// eventually return the response object
And here are the server logs
querying db
POST <route> <status code> 49.810 ms - 9 //<- and this is the appropriate response
done querying the db
... other stuff
When I the function is modified so that the map function doesn't return anything, (a) it doesn't query the database, and (b) doesn't return the express response object early. So by modifying this:
const records = await Promise.all(Object.keys(params).map(function(table){
return db[table].find({ // going to delete the `return` command here
_id: {
$in: params[table]._ids
}
})
}))
to this
const records = await Promise.all(Object.keys(params).map(function(table){
db[table].find({ // not returning this out of map
_id: {
$in: params[table]._ids
}
})
}))
the server logs change to:
querying db
done querying the db
... other stuff
POST <route> <status code> 49.810 ms - 9 // <-appropriate reponse
But then I'm not actually building my query, so the query response is empty. I'm experiencing this behavior with the anonymous map function being an arrow function of this format .map(table => (...)) as well.
Any ideas what's going on, why, or suggestions?
Your first version of your code is working as expected and the logs are as expected.
All async function return a promise. So findInDB_by_id() will always return a promise. In fact, they return a promise as soon as the first await inside the function is encountered as the calling code continues to run. The calling code itself needs to use await or .then() to get the resolved value from that promise.
Then, some time later, when you do a return someValue in that function, then someValue becomes the resolved value of that promise and that promise will resolve, allowing the calling code to be notified via await or .then() that the final result is now ready.
await only suspends execution of the async function that it is in. It does not cause the caller to be blocked at all. The caller still has to to deal with a promise returned from the async function.
The second version of your code just runs the db queries open loop with no control and no ability to collect results or process errors. This is often referred to as "fire and forget". The rest of your code continues to execute without regard for anything happening in those db queries. It's highly unlikely that the second version of code is correct. While there are a very few situations where "fire and forget" is appropriate, I will always want to at least log errors in such a situation, but since it appears you want results, this cannot be correct
You should try something like as when it encounter first async function it start executing rest of the code
let promiseArr = []
Object.keys(params).map(function(table){
promiseArr.push(db[table].find({
_id: {
$in: params[table]._ids
}
}))
})
let [records] = await Promise.all(promiseArr)
and if you still want to use map approach
await Promise.all(Object.keys(params).map(async function(table){
return await db[table].find({
_id: {
$in: params[table]._ids
}
})
})
)

Unable to find the source of error dialogflow fulfillment

I am trying to create intent in which when the user sends a parameter, then it should be checked in the database that is already there or not. If it already exists user gets a response A and if not it is added to the database, & the user gets response B. I am using Axios to make the API calls. But the code is not working.
I am getting a following errors in the console.
TypeError: Cannot set property 'response' of undefined
at axios.get.then.response (/srv/index.js:33:18)
at <anonymous>
at process._tickDomainCallback (internal/process/next_tick.js:229:7)"
Show matching entries
Hide matching entries
Add field to summary line
I am not a professional, I am doing all this coding by learning from online tutorials and youtube videos Please help.
function idHandler(agent) {
const idcard = agent.parameters.idcard;
const idvalue = ' ';
const idname= ' ';
axios.get('API' + idcard)
.then(response => {
this.response = response.data;
idvalue = this.response[0].IDcard;
idname = this.response[0].Name;
});
if (idcard === idvalue) {
const ans = 'Name of ' + idname + ' is already present in the List';
agent.add(ans);
} else {
const data = [{
idcard: idcard
}];
axios.post('API', data);
}
}
You have a few issues with both how to code for Dialogflow, and how to express some of the syntax correctly. Some of that is because it looks like you're mixing code that expects Promises with code that doesn't.
The axios library is meant to work with Promises - the get and post methods both return Promises. So you can either work with them by using an await method, or by using the .then() method that the returned Promise has. You may want to look up details of both.
Additionally, Dialogflow requires that you either return the Promise, or that your handler be an async function (which will return a Promise for you).
If you're using the .then() approach, however, then everything you do that relies on the call to axios must be done inside the .then() block and you must return that Promise. If you use await, then your function must be declared as an async function. (You can probably mix the two - but don't.)
So that part of your code might look something like:
return axios.get( url )
.then( response => {
// Do EVERYTHING in here
});
And inside the then() code block is where you would extract the values you want, call agent.add() with the message, and possibly make the API call to add data.
While this didn't get flagged as an error, you are trying to assign a value to a const after it is initially set. This is an error. Those should probably be declared using let instead.
Your error looks like it is saying that this is undefined. Which seems... odd. But also not really an issue since you probably don't need to be using this for most of what you're trying to do. If you scope the variables with let, then they should be available for the life of the function.

Node.js waiting for an async Redis hgetall call in a chain of functions

I'm still somewhat new to working with Node and def new to working asynchronously and with promises.
I have an application that is hitting a REST endpoint, then calling a chain of functions. The end of this chain is calling hgetall and I need to wait until I get the result and pass it back. I'm testing with Postman and I'm getting {} back instead of the id. I can console.log the id, so I know that this is because some of the code isn't waiting for the result of hgetall before continuing.
I'm using await to wait for the result of hgetall, but that's only working for the end of the chain. do I need to do this for the entire chain of functions, or is there a way to have everything wait for the result before continuing on? Here's the last bit of the logic chain:
Note: I've removed some of the logic from the below functions and renamed a few things to make it a bit easier to see the flow and whats going on with this particular issue. So, some of it may look a bit weird.
For this example, it will call GetProfileById().
FindProfile(info) {
var profile;
var profileId = this.GenerateProfileIdkey(info); // Yes, this will always give me the correct key
profile = this.GetProfileById(profileId);
return profile;
}
This checks with the Redis exists, to verify if the key exists, then tries to get the id with that key. I am now aware that the Key() returns true instead of what Redis actually returns, but I'll fix that once I get this current issue resolved.
GetProfileById(profileId) {
if ((this.datastore.Key(profileId) === true) && (profileId != null)) {
logger.info('GetProfileById ==> Profile found. Returning the profile');
return this.datastore.GetId(profileId);
} else {
logger.info(`GetProfileById ==> No profile found with key ${profileId}`)
return false;
}
}
GetId() then calls the data_store to get the id. This is also where I started to use await and async to try and wait for the result to come through before proceeding. This part does wait for the result, but the functions prior to this don't seem to wait for this one to return anything. Also curious why it only returns the key and not the value, but when I print out the result in hgetall I get the key and value?
async GetId(key) {
var result = await this.store.RedisGetId(key);
console.log('PDS ==> Here is the GetId result');
console.log(result); // returns [ 'id' ]
return result;
}
and finally, we have the hgetall call. Again, new to promises and async, so this may not be the best way of handling this or right at all, but it is getting the result and waiting for the result before it returns anything
async RedisGetId(key) {
var returnVal;
var values;
return new Promise((resolve, reject) => {
client.hgetall(key, (err, object) => {
if (err) {
reject(err);
} else {
resolve(Object.keys(object));
console.log(object); // returns {id: 'xxxxxxxxxxxxxx'}
return object;
}
});
});
}
Am I going to need to async every single function that could potentially end up making a Redis call, or is there a way to make the app wait for the Redis call to return something, then continue on?
Short answer is "Yes". In general, if a call makes an asynchronous request and you need to await the answer, you will need to do something to wait for it.
Sometimes, you can get smart and issue multiple calls at once and await all of them in parallel using Promise.all.
However, it looks like in your case your workflow is synchronous, so you will need to await each step individually. This can get ugly, so for redis I typically use something like promisify and make it easier to use native promises with redis. There is even an example on how to do this in the redis docs:
const {promisify} = require('util');
const getAsync = promisify(client.get).bind(client);
...
const fooVal = await getAsync('foo');
Makes your code much nicer.

How to stop class/functions from continuing to execute code in Node.js

I have made a few questions about this already, but maybe this question would result in better answers(i'm bad at questions)
I have one class, called FOO, where I call an async Start function, that starts the process that the class FOO was made to do. This FOO class does a lot of different calculations, as well as posting/getting the calculations using the node.js "requets" module.
-I'm using electron UI's (by pressing buttons, that executes a function etc..) to create and Start the FOO class-
class FOO {
async Start(){
console.log("Start")
await this.GetCalculations();
await this.PostResults()
}
async PostResults(){
//REQUESTS STUFF
const response = {statusCode: 200} //Request including this.Cal
console.log(response)
//Send with IPC
//ipc.send("status", response.statusCode)
}
async GetCalculations(){
for(var i = 0; i < 10; i++){
await this.GetCalculation()
}
console.log(this.Cal)
}
async GetCalculation(){
//REQUEST STUFF
const response = {body: "This is a calculation"} //Since request module cant be used in here.
if(!this.Cal) this.Cal = [];
this.Cal.push(response)
}
}
var F1 = new FOO();
F1.Start();
Now imagine this code but with A LOT more steps and more requests ect. where it might take seconds/minutes to finish all tasks in the class FOO.
-Electron got a stop button that the user can hit when he wants the calculations to stop-
How would I go about stopping the entire class from continuing?
In some cases, the user might stop and start right after, so I have been trying to figure out a way to STOP the code from running entirely, but where the user would still be able to create a new class and start that, without the other class running in the background.
I have been thinking about "tiny-worker" module, but on the creation of the worker, it takes 1-2 seconds, and this decreases the purpose of a fast calculation program.
Hopefully, this question is better than the other ones.
Update:
Applying the logic behind the different answers I came up with this:
await Promise.race([this.cancelDeferred, new Promise( async (res, req) => {
var options ={
uri: "http://httpstat.us/200?sleep=5000"
}
const response = await request(options);
console.log(response.statusCode)
})])
But even when the
this.cancelDeferred.reject(new Error("User Stop"));
Is called, the response from the request "statuscode" still gets printed out when the request is finished.
The answares I got, shows some good logic, that I didn't know about, but the problem is that they all only stop the request, the code hanlding the request response will still execute, and in some cases trigger a new request. This means that I have to spam the Stop function until it fully stops it.
Framing the problem as a whole bunch of function calls that make serialized asynchronous operations and you want the user to be able to hit a Cancel/Stop button and cause the chain of asynchronous operations to abort (e.g. stop doing any more and bail on getting whatever eventual result it was trying to get).
There are several schemes I can think of.
1. Each operation checks some state property. You make these operations all part of some object that has a aborted state property. The code for every single asynchronous operation must check that state property after it completes. The Cancel/Stop button can be hooked up to set this state variable. When the current asynchronous operation finishes, it will abort the rest of the operation. If you are using promises for sequencing your operations (which it appears you are), then you can reject the current promise causing the whole chain to abort.
2. Create some async wrapper function that incorporates the cancel state for you automatically. If all your actual asynchronous operations are of some small group of operations (such as all using the request module), then you can create a wrapper function around whichever request operations you use that when any operation completes, it checks the state variable for you or merges it into the returned promise and if it has been stopped, it rejects the returned promise which causes the whole promise chain to abort. This has the advantage that you only have to do the if checks in one place and the rest of your code just switches to using your wrapped version of the request function instead of the regular one.
3. Put all the async steps/logic into another process that you can kill. This seems (to me) like using a sledge hammer for a small problem, but you could launch a child_process (which can also be a node.js program) to do your multi-step async operations and when the user presses stop/cancel, then you just kill the child process. Your code that is monitoring the child_process and waiting for a result will either get a final result or an indication that it was stopped. You probably want to use an actual process here rather than worker threads so you get a full and complete abort and so all memory and other resources used by that process gets properly reclaimed.
Please note that none of these solutions use any sort of infinite loop or polling loop.
For example, suppose your actual asynchronous operation was using the request() module.
You could define a high scoped promise that gets rejected if the user clicks the cancel/stop button:
function Deferred() {
let p = this.promise = new Promise((resolve, reject) => {
this.resolve = resolve;
this.reject = reject;
});
this.then = this.promise.then.bind(p);
this.catch = this.promise.catch.bind(p);
this.finally = this.promise.finally.bind(p);
}
// higher scoped variable that persists
let cancelDeferred = new Deferred();
// function that gets called when stop button is hit
function stop() {
// reject the current deferred which will cause
// existing operations to cancel
cancelDeferred.reject(new Error("User Stop"));
// put a new deferred in place for future operations
cancelDeferred = new Deferred();
}
const rp = require('request-promise');
// wrapper around request-promise
function rpWrap(options) {
return Promise.race([cancelDeferred, rp(options)]);
}
Then, you just call rpWrap() everywhere instead of calling rp() and it will automatically reject if the stop button is hit. You need to then code your asynchronous logic so that if any reject, it will abort (which is generally the default and automatic behavior for promises anywa).
Asynchronous functions do not run code in a separate thread, they just encapsulate an asynchronous control flow in syntactic sugar and return an object that represents its completion state (i.e. pending / resolved / rejected).
The reason for making this distinction is that once you start the control flow by calling the async function, it must continue until completion, or until the first uncaught error.
If you want to be able to cancel it, you must declare a status flag and check it at all or some sequence points, i.e. before an await expression, and return early (or throw) if the flag is set. There are three ways to do this.
You can provide a cancel() function to the caller which will be able set the status.
You can accept an isCancelled() function from the caller which will return the status, or conditionally throw based on the status.
You can accept a function that returns a Promise which will throw when cancellation is requested, then at each of your sequence points, change await yourAsyncFunction(); to await Promise.race([cancellationPromise, yourAsyncFunction()]);
Below is an example of the last approach.
async function delay (ms, cancellationPromise) {
return Promise.race([
cancellationPromise,
new Promise(resolve => {
setTimeout(resolve, ms);
})
]);
}
function cancellation () {
const token = {};
token.promise = new Promise((_, reject) => {
token.cancel = () => reject(new Error('cancelled'));
});
return token;
}
const myCancellation = cancellation();
delay(500, myCancellation.promise).then(() => {
console.log('finished');
}).catch(error => {
console.log(error.message);
});
setTimeout(myCancellation.cancel, Math.random() * 1000);

Resources