Retry promise himself after fail in node js - javascript

I would like to retry my request in a promise. I would like launch my refresh if I have always an 401 error as a loop : (if I have 401 loop on refresh until 200)
I tried with this :
const request = require('request');
let conf = require('../conf');
let core_service = require('coreService');
let self = module.exports = {
get_count_questions: function() {
return new Promise((resolve, reject) => {
request({
method: 'GET',
uri: 'http://api/count-questions',
auth: {
'bearer': conf.token
},
json: true
}, function (error, response, body) {
if (!error && response.statusCode === 200) {
resolve(body);
} else if (!error && response.statusCode === 401) {
core_service.refreshToken().then((data) => {
console.log('token refresh');
return self.get_count_questions();
})
} else {
reject(error);
}
})
});
}
};
I tried with just 'self.get_count_questions();' without return, but it's not work. I have not error message, just my app freeze.
I see in my console.log "token refresh", but after my app freeze...
Edit
I modified with this, It's like better but the refresh token it's very slow. Just before 401, my app stop, and after about 1 minutes 40 seconds, run:
else if (!error && response.statusCode === 401) {
console.log('need refresh token');
core_service.refreshToken()
.then((response) => {
console.log(response);
resolve(self.get_count_questions())
} );
}
My refreshToken function :
refreshToken: function () {
return new Promise((resolve, reject) => {
request({
method: 'GET',
uri : 'http://api/refresh',
auth : {
'bearer': conf.token
},
json : true
}, function (error, response, body) {
console.log('=====> refresh token <======');
conf.token = body.data;
console.log('new Token');
console.log('=====> end refresh token <======');
if (!error && response.statusCode === 200) {
resolve('Refresh token successful');
} else {
reject('Error refresh');
}
})
});
}
If I refresh my token on each request, I have a problem :
if (!error && response.statusCode === 200) {
core_service.refreshToken().then((data)=> {
resolve(body);
});
}

You have to resolve the returned promise. When you resolve using a promise, you basically say, complete this promise with the result of that promise.
var prom = function() {
return new Promise((resolve, reject) => {
console.log('request start')
setTimeout(() => {
console.log('request finish')
let ran = Math.random();
if (ran < 0.1)
resolve('success');
else if (ran >= 0.1 && ran < 0.98)
setTimeout(() => {
console.log('retry');
resolve(prom());
}, 500);
else
reject('error');
}, 500);
});
};
prom().then(console.log.bind(console), console.log.bind(console));
So you should update your else if block like this:
else if (!error && response.statusCode === 401) {
console.log('need refresh token');
core_service.refreshToken()
.then(() => resolve(self.get_count_questions()));
}

You're making a recursive call, but you're never actually doing anything with its promise. Therefore, your original promise never resolves.
You need to pass the promise from the recursive call (to refreshToken().then()) to resolve().

Now you almost have it.
However:
return core_service.refreshToken()
.then(self.get_count_questions);
You're returning that to the request() callback; that return value is not used.
Instead, you need to resolve your original promise to the new promise from then(), by passing it to your original resolve() function:
resolve(core_service.refreshToken().then(...));

I know that is not optimal solution but it might helps
const request = require('request');
let conf = require('../conf');
let core_service = require('coreService');
let self = module.exports = {
get_count_questions: function() {
return new Promise((resolve, reject) => {
request({
method: 'GET',
uri: 'http://api/count-questions',
auth: {
'bearer': conf.token
},
json: true
}, function (error, response, body) {
try{
if (!error && response.statusCode === 200) {
resolve(body);
} else if (!error && response.statusCode === 401) {
throw new Error(response.statusCode);
} else {
reject(error);
}
}catch(exc){if(exc === 401){
core_service.refreshToken().then((data) => {
console.log('token refresh');
return self.get_count_questions();
})
}
}
})
});
}
};

You need to call the initial resolve/reject functions after you retried the request:
let self = module.exports = {
get_count_questions: function() {
return new Promise((resolve, reject) => {
request({
method: 'GET',
uri: 'http://api/count-questions',
auth: {
'bearer': conf.token
},
json: true
}, function (error, response, body) {
if (!error && response.statusCode === 200) {
resolve(body);
} else if (!error && response.statusCode === 401) {
core_service.refreshToken().then((data) => {
console.log('token refresh');
self.get_count_questions().then((data) => {
// call initial resolve function
resolve(data);
}).catch((error) => {
// call initial reject function
reject(error);
});
}).catch((error) => {
// reject if refreshToken fails
reject(error);
});
} else {
reject(error);
}
})
});
}
};
You also have to make sure, that the second call actually resolves/rejects and doesn't land in another 401. Because else you have an infinite recursion.

Related

Request Params Node JS 500 Error

As the uri is generated is as expected and list data is shown in page but while sending the req in request method, 500 error occurs instead of retruning body.
uri: http://yufluyuinnepal.com/?vTRIPTYPE=O&vOPSID=O&vSTRFROM=KTM&vSTRFROMTXT=&vSTRTO=PKR&vSTRTOTXT=&vFLIGHTDATE=27-Nov-2018&vRETURNDATE=27-Nov-2018&vADULT=1&vCHILD=0&vNATIONALITY=NP&vNATIONALITYTXT=Nepal&
const uri = `http://yufluyuinnepal.com/?${queryString(query)}`;
console.log(uri);
const req = {
uri: uri,
};
request(req, (error, response, body) => {
if (error) {
return reject(error);
}
if (response.statusCode !== 200) {
return reject(new Error(`Expected 200 but got ${response.statusCode}`));
}
return resolve(body);
});
Let me know how can i return body and what is wrong in my code.
In Request npm module, specify what kind of request is it (GET/POST etc)
// Example GET Request
var options = {
method: "GET",
url:
uri,
headers:
{
// headers as per documentation
}
};
request(options, (error, response, body) => {
if(error){}
if(response.statusCode !== 200){}
return resolve(body);
})
This is your current implementation with a callback function.
const req = {
uri: uri,
method: 'GET'/'POST'
};
request(req, (error, response, body) => {
if (error) {
console.log(error);
}
if (response.statusCode !== 200) {
//Do something
}
console.log(body);
//Do something
});
When using request-promise module you should write something like this
var rp = require('request-promise');
const req = {
uri: uri,
method: 'GET'/'POST'
}
rp(req)
.then((res) => {
//Do something
})
.catch((error) => {
//Do something with error
});
Please try this
let requestp=require('request-promise');
var options = {
    method: 'POST',
    url: 'uri',
    resolveWithFullResponse: true,
    headers: {
                'Accept': 'application/json',
                'Content-Type' : 'application/json'
            },
            body: TextedValue
        };
     
        await  requestp(options).then(async function(Content){
           await requestp(options).then(async function(response){
                if (await response.statusCode == 200)
                    {
                        console.log(Content); // in ur case it is body
                    }
                 else
                    {
                        console.log("Response code "+response.statusCode+" .Try Again Later")
                   }
                })
           })

Node.js execution doesn't continue after function in if-statement

This snippet of code gets executed until the end of the getRefreshToken function is at its last line. The play_song function does not get triggered.
Am I misunderstanding the way JS works? For now I have included the call to play_song at the end of the getRefreshToken function, and of course that works as expected. However, I am very confused why it doesn't just execute function after function in the if-statement.
function checkTime () {
var now = new Date();
if (now.getHours() == time[0] && now.getMinutes() == time[1]) {
getRefreshToken();
play_song();
}
}
The contents of getRefreshToken:
function getRefreshToken() {
console.log('Starting token request')
// requesting access token from refresh token
var refresh_token = tokens.refresh;
var authOptions = {
url: 'https://accounts.spotify.com/api/token',
headers: { 'Authorization': 'Basic ' + (new Buffer(client_id + ':' + client_secret).toString('base64')) },
form: {
grant_type: 'refresh_token',
refresh_token: refresh_token
},
json: true
};
request.post(authOptions, function(error, response, body) {
if (!error && response.statusCode === 200) {
tokens.access = body.access_token;
}
//play_song(); //only a temporary fix
})
}
Yes in JavaScript, functions are not necessarily synchronous as you might be familiar with in other programming languages. JavaScript is single threaded, however operations such as fetching data, querying API's, databases, I/O etc. all happen in parallel to the main execution of your code.
I assume getRefreshToken() is making some sort of network request and the fact you mentioned play_song works when put at the end of getRefreshToken() gives it away.
There are many ways to deal with this in JavaScript, here's a good resource.
Here's an example for your situation, I removed some unneeded code for the purpose of the example:
// Using callbacks
function checkTime() {
getRefreshToken(play_song);
}
function getRefreshToken(callback) {
request.post(authOptions, function(error, response, body) {
if (!error && response.statusCode === 200) {
tokens.access = body.access_token;
}
callback();
})
}
// Using Promises
function checkTime() {
getRefreshToken()
.then(() => {
play_song();
})
}
function getRefreshToken(callback) {
return new Promise((resolve, reject) => {
request.post(authOptions, function(error, response, body) {
if (!error && response.statusCode === 200) {
tokens.access = body.access_token;
}
resolve();
})
})
}
// Using Async/Await
async function checkTime() {
await getRefreshToken()
play_song();
}
function getRefreshToken(callback) {
return new Promise((resolve, reject) => {
request.post(authOptions, function(error, response, body) {
if (!error && response.statusCode === 200) {
tokens.access = body.access_token;
}
resolve();
})
})
}

Again about async/await in javascript

My function looks like this now:
var GetImages = async() => {
var images_array = [];
await request ({
url: `https://api.tumblr.com/v2/blog/nameblog/posts?api_key=${process.env.TUMBLR_KEY}&type=photo`,
json: true
}, (error, response, body) => {
if(error){
console.log('Unable to connect');
}else if(body.meta.status === "ZERO_RESULTS"){
console.log('Uable to find that address.');
}else if(body.meta.status === 200){
body.response.posts.forEach(function(obj) {
obj.photos.forEach(function(photo) {
if(photo.original_size.width>photo.original_size.height){
images_array.push(photo.original_size.url);
console.log("dawdaw");
}
});
});
//callback(images_array);
}
});
return images_array;
}
I have no idea, how return my array after i'll fill it with values. With callback it works fine, but i wanna do it with async/await methid in right way. Thank you for help.
create method to return promise for request and use that method with await
requestPromise = () => {
return new Promise(function(resolve, reject) {
request({
url: `https://api.tumblr.com/v2/blog/nameblog/posts?api_key=${process.env.TUMBLR_KEY}&type=photo`,
json: true
}, (error, response, body) => {
if (error) {
console.log('Unable to connect');
reject();
} else if (body.meta.status === "ZERO_RESULTS") {
console.log('Uable to find that address.');
reject();
} else if (body.meta.status === 200) {
body.response.posts.forEach(function(obj) {
obj.photos.forEach(function(photo) {
if (photo.original_size.width > photo.original_size.height) {
images_array.push(photo.original_size.url);
console.log("dawdaw");
}
});
});
resolve(images_array)
}
});
});
}
var GetImages = async() => {
try
{
images = await requestPromise();
return images;
}
catch(e){return [];}
}

JavaScript Promise - how to make multiple promise?

How can I chain the multiple promise? For instance:
var promise = new Promise(function(resolve, reject) {
// Compose the pull url.
var pullUrl = 'xxx';
// Use request library.
request(pullUrl, function (error, response, body) {
if (!error && response.statusCode == 200) {
// Resolve the result.
resolve(true);
} else {
reject(Error(false));
}
});
});
promise.then(function(result) {
// Stop here if it is false.
if (result !== false) {
// Compose the pull url.
var pullUrl = 'xxx';
// Use request library.
request(pullUrl, function (error, response, body) {
if (!error && response.statusCode == 200) {
resolve(body); // <-- I want to pass the result to the next promise.
} else {
reject(Error(false));
}
});
}
}, function(err) {
// handle error
});
promise.then(function(result) {
// Stop here if it is false.
if (result !== false) {
// handle success.
console.log(result);
}
}, function(err) {
// handle error.
});
Error:
resolve(body);
ReferenceError: resolve is not defined
Any ideas?
When chaining Promises, then return value from a function given to then should either be a Promise, or the value to pass along.
In your case, since you're making an async call, you'll just return another promise and call reject or resolve within there. If it wasn't async, you could just return the value, or throw an error, which also gets passed along to the next then or error handler/catch as appropriate.
Also, you need to chain them together, because each then() returns a different Promise.
So, something like this:
var promise = new Promise(function(resolve, reject) {
// Compose the pull url.
var pullUrl = 'xxx';
// Use request library.
request(pullUrl, function (error, response, body) {
if (!error && response.statusCode == 200) {
// Resolve the result.
resolve(true);
} else {
reject(Error(false));
}
});
});
promise.then(function(result) {
// Stop here if it is false.
if (result !== false) {
var airportCode = result;
// Compose the pull url.
var pullUrl = 'xxx';
// Use request library.
return new Promise(function (resolve, reject) {
request(pullUrl, function (error, response, body) {
if (!error && response.statusCode == 200) {
resolve(body);
} else {
reject(Error(false));
}
});
});
}
}).then(function(result) {
// Stop here if it is false.
if (result !== false) {
// handle success.
console.log(result);
}
}).catch(function (err) {
// handle error
});
Here is a JSFiddle with a working version: JSFiddle

Node JS: Request Loop Until Status Code 200

I currently have working code that does a request and checks if it receives a successful status code of 200. I would like to grow on this and loop it where it will keep sending requests until the status code is 200. I tried using a while loop but was not receiving the correct results. Thanks for the help!
request('http://0.0.0.0:9200', function (error, response, body) {
if (!error && response.statusCode == 200) {
console.log('success');
do(something);
}
else {
console.log('fail');
}
});
Would be something like:
let retry = (function() {
let count = 0;
return function(max, timeout, next) {
request('http://0.0.0.0:9200', function (error, response, body) {
if (error || response.statusCode !== 200) {
console.log('fail');
if (count++ < max) {
return setTimeout(function() {
retry(max, timeout, next);
}, timeout);
} else {
return next(new Error('max retries reached'));
}
}
console.log('success');
next(null, body);
});
}
})();
retry(20, 1000, function(err, body) {
do(something);
});
You can set a max number of retries and a timeout between retries. So that you do not introduce an infinite loop, and you do not deliver the final punch to an overloaded request target ^^
I wanted a little more intuitive answer including promises. I build on top of miggs answer within a try/catch the code below with promises and axios.
Based on a simple example of recursive functions
const throwNumbers = (count = 0) => {
console.log(count);
if (count++ < 10) {
throwNumbers(count);
} else {
console.log('max reached');
};
};
You can put anything else on the try part and handle error codes in the catch part. You have to set a max number of retries, which is 10 in my case.
let getResponse = async(count = 0) => {
try {
const axiosResponse = await axios.get(someURL, {
params: {
parameter1: parameter1,
},
});
return axiosResponse;
} catch (error) {
if (error || error.status != 200) {
console.error('failed, retry');
if (count++ < 10) {
return getResponse(count);
} else {
throw new Error('max retries reached');
};
} else {
throw error;
};
};
};
You would call the function with the following and handle the body or whatever with the response value.
let response = await getResponse();
console.log('This is the response:', response);
Has no timeout but works for me.

Categories

Resources