JavaScript Try catch how to call same function in catch to retry - javascript

In JavaScript Try catch block how to retry the same . am facing once scenario any one ca give the best approach to handle this ?
for Example :
const getMyDetails = async()=>{
try{
await getName();
}catch(err){
//But Above FAIL due to some issue
// so I want to try the same again "getName" here until the success - 'not single time'
}
// Second Method for get data
const getName = async()=>{
try{
here am calling API or any kind of subscription But here its failing so am throwing error
}catch(err){
throw new Error(err);
}
getMyDetails()
Note: may be the fail reason like Databse events or some other subscriptions etc..
instead of calling the method name in catch .. what will be the best approach for retry
Thanks in advance

Just Calling Itself If It Fails Will Do The Job
const getMyDetails = async()=>{
try{
await getName();
}catch(err){
getMyDetails()
}
// Second Method for get data
const getName = async()=>{
try{
// Method
}catch(err){
throw new Error(err);
}
getMyDetails()

Here you can see an example behavior and the implementation logic of calling an async function N number of times, only until no errors are thrown.
// We must be inside of an async function to be able to call await
(async function() {
// Example async function which returns the value only if no errors are thrown,
// otherwise calls itself to retry the async call
async function getMyDetails() {
try {
return await getName();
} catch (error) {
return getMyDetails();
}
}
// Example async function which returns value only if the random number is even,
// otherwise throws an Error (simulating an API error response)
async function getName() {
return new Promise((resolve, reject) => {
let randomNumber = Math.floor(Math.random());
if (randomNumber % 2 === 0) {
resolve("Random Name");
}
reject("Example API Error has occured.")
});
}
let myDetails = await getMyDetails();
console.log(myDetails);
})();

Related

How to stop running async function on node.js from react application?

React app can run node.js function which preparing data and sending information to the database in batches.
It takes a lot of time and I would like to add the ability to stop this function right from react app.
const getShopifyOrders = require('./shopify');
const getTrack = require('./tracking');
const Order = require('./model');
async function addOrdersToDB(limit) {
try {
// Get latest order from DB
let latestOrd = await Order.findOne().sort('-order_number');
do {
// Get Shopify Orders
let orders = await getShopifyOrders(
latestOrd ? latestOrd.order_id : 0,
limit
);
latestOrd = orders[0] ? orders[orders.length - 1] : undefined;
// Update array with tracking status
let fullArray = await getTrack(orders);
// Add to DB
let ins = await Order.insertMany(fullArray, { ordered: false });
console.log(`Added ${ins.length} entries`);
} while (latestOrd);
} catch (err) {
console.log(err);
}
}
module.exports = addOrdersToDB;
I tried a lot of things to include in this function including:
while loop: added the variable outside the function - if 'true' - run code, if not - return - it just doesn't work (variable was changed from react using socket.IO)
setTimeout (also setInterval), triger clearTimeout function from react: this doesn't work as setTimeout and setInterval doesn't work in async function
after that:
made (actually fond here on stackoverflow) new function to promisify setTimeout to be able to use in async function:
const setTimeout2 = (callback, ms) => {
return new Promise(
resolve =>
(to = setTimeout(() => {
callback();
resolve();
}, ms))
);
};
async function addOrdersToDB(limit) {
do {
await setTimeout2(async () => {
try {
// some code here
} catch (err) {
console.log(err);
}
}, 400);
} while (latestOrderExist);
}
function clearTO() {
setTimeout(() => {
console.log('clearTO');
clearTimeout(to);
}, 3000);
}
This for some reason doesn't iterate.
Is there solution for this?
Thanks!
To abort the do/while loop, you will need to add an additional test to that loop that is some variable that can be modified from the outside world. Also, note that the additional test only works here because you're using await inside the loop. If there was no await inside the loop, then the loop would be entirely synchronous and there would be no ability to change a variable from outside the loop while the loop was running (because of nodejs' single-threadedness).
Since this is a server (and globals are generally bad), I will assume we should not use a global. So instead, I would restructure addOrdersToDB() to return a data structure that contains both the promise the existing version returns and an abort() function the caller can call to stop the current processing. This also permits multiple separate calls to addOrdersToDB() to be running, each with their own separate abort() method.
function addOrdersToDB(limit) {
let stop = false;
function abort() {
stop = true;
}
async function run() {
try {
// Get latest order from DB
let latestOrd = await Order.findOne().sort('-order_number');
do {
// Get Shopify Orders
let orders = await getShopifyOrders(
latestOrd ? latestOrd.order_id : 0,
limit
);
latestOrd = orders[0] ? orders[orders.length - 1] : undefined;
// Update array with tracking status
let fullArray = await getTrack(orders);
// Add to DB
let ins = await Order.insertMany(fullArray, { ordered: false });
console.log(`Added ${ins.length} entries`);
} while (!stop && latestOrd);
// make resolved value be a boolean that indicates
// whether processing was stopped with more work still pending
return !!(latestOrd && stop);
} catch (err) {
// log error and rethrow so caller gets error propagation
console.log(err);
throw err;
}
}
return {
promise: run(),
abort: abort
}
}
So, to use this, you would have to change the way you call addOrdersToDB() (since it no longer returns just a promise) and you would have to capture the abort() function that it returns. Then, some other part of your code can call the abort() function and it will then flip the internal stop variable that will cause your do/while loop to stop any further iterations.
Note, this does not stop the asynchronous processing inside the current iteration of the do/while loop - it just stops any further iterations of the loop.
Note, I also changed your catch block so that it rethrows the error so that the caller will see if/when there was an error.
And, the resolved value of the function is the internal stop variable so the caller can see if the loop was aborted or not. A true resolved value means the loop was aborted and there was more work to do.
Here's an additional version of the function that creates more opportunities for it to stop between await operations within your function and within the loop. This still does not abort an individual database operation that may be in progress - you'd have to examine whether your database supports such an operation and, if so, how to use it.
function addOrdersToDB(limit) {
let stop = false;
function abort() {
stop = true;
}
async function run() {
try {
// Get latest order from DB
let latestOrd = await Order.findOne().sort('-order_number');
if (!stop) {
do {
// Get Shopify Orders
let orders = await getShopifyOrders(
latestOrd ? latestOrd.order_id : 0,
limit
);
latestOrd = orders[0] ? orders[orders.length - 1] : undefined;
if (stop) break;
// Update array with tracking status
let fullArray = await getTrack(orders);
if (stop) break;
// Add to DB
let ins = await Order.insertMany(fullArray, { ordered: false });
console.log(`Added ${ins.length} entries`);
} while (!stop && latestOrd);
}
// make resolved value be a boolean that indicates
// whether processing was stopped with more work still pending
return !!(latestOrd && stop);
} catch (err) {
// log and rethrow error so error gets propagated back to cller
console.log(err);
throw err;
}
}
return {
promise: run(),
abort: abort
}
}

Should the inner function or the calling function be wrapped within a try-catch block for correct error handling? [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 2 years ago.
Improve this question
Should the inner function or the calling function be wrapped within a try-catch block for correct error handling?
Example 1
// Async function definition
const getLatestRecords = async() => {
try {
const records = await Record.find({})
return records
} catch(e) {
console.error(e)
}
}
// Async function call without error handling - will this suffice?
let records
const callAsyncFunction = async() => {
records = await getLatestRecords()
}
callAsyncFunction()
// Same async function call with error handling - or should it be like this?
let records
const callAsyncFunctionWithTryCatch = async() => {
try {
records = await getLatestRecords()
} catch(e) {
console.error(e)
}
}
callAsyncFunctionWithTryCatch()
Q1) In the example above, the async function definition getLatestRecords() is already wrapped in a try-catch block for error handling. In spite of this, is the calling function as defined by callAsyncFunction() enough or should the async function call also be wrapped in a try-catch block as demonstrated by callAsyncFunctionWithTryCatch()?
Example 2
// Test without try catch block - will this suffice?
test('Should delete records with valid id', async() => {
const record = await new Record().save()
const res = await request(app)
.delete(`/records/${record._id}`)
.expect(200)
expect(await Records.countDocuments()).toBe(0)
})
// Test with try catch block - should all tests with await in them be wrapped in a try catch block?
test('Should delete records with valid id', async() => {
try {
const record = await new Record().save()
const res = await request(app)
.delete(`/records/${record._id}`)
.expect(200)
expect(await Records.countDocuments()).toBe(0)
} catch(e) {
console.error(e)
}
})
Q2) Similarly, for tests, should all tests with await calls in them be wrapped in a try catch block? Keep in mind, that one wants a test to fail if something goes wrong so I am not totally sure about this one.
You should only enclose them in try/catch if you know you can handle everything regarding the error in that function. Otherwise, you should let the consumer of the function decide what to do with errors. For example, with getLatestRecords, if there are various different points around the script where it's used, it would probably make the most sense to let those different points handle errors, depending on their context. For example:
const getLatestRecords = async () => {
const records = await Record.find({})
return records
}
// could also just do: `return Record.find({})`
getLatestRecords()
.then(doStuff)
.catch((err) => {
res.status(500).send('Could not retrieve records for ' + user);
});
If you put the try/catch inside the inner getLatestRecords function, on the other hand, consumers will have to check if an error occurred by checking whether the return value exists, rather than .catch, which is a bit strange.
If all awaits are inside try/catch, the containing async function will never reject. So, having the caller of that async function put it inside try/catch won't accomplish anything, because the inner function will never reject; the catch will never be entered. That is, for this example:
const getLatestRecords = async() => {
try {
const records = await Record.find({})
return records
} catch(e) {
console.error(e)
}
}
const callAsyncFunctionWithTryCatch = async() => {
try {
records = await getLatestRecords()
} catch(e) {
console.error(e)
}
}
callAsyncFunctionWithTryCatch()
it's superfluous; simplify it to
const getLatestRecords = async() => {
try {
const records = await Record.find({})
return records
} catch(e) {
console.error(e)
}
}
const callAsyncFunctionWithTryCatch = async() => {
records = await getLatestRecords()
}
callAsyncFunctionWithTryCatch()
(or catch in callAsyncFunctionWithTryCatch only - but don't catch in both)
should the async function call also be wrapped in a try-catch block
If a an async function is wrapped in try/catch, you don't need it on multiple levels unless there is some code which can throw error and is not wrapped by a try/catch. eg:
const getLatestRecords = async() => {
aFunctionWhichCanThrow(); // <= Only need try/catch in caller fn for this
try {
const records = await Record.find({})
return records
} catch(e) {
console.error(e)
}
}
Even in that case, you might want to handle the errors through a global unhandledRejection handler.
should all tests with await calls in them be wrapped in a try catch block
Yes, tests which can throw/reject should be wrapped in a try/catch block. The ise cases can be like:
Function is supposed to not throw
try - verify the function response
catch - fail the test
Function is supposed to throw
try - fail the test
catch - verify the error

Node JS - How to return response from nested function?

Is it possible to return a response when call a function within another function?
I have following codes -
// Add Category
exports.saveCategory = async function(catData, callback){
try{
const images = await uploadImages(catData.files);
console.log(images); //nothing prints here
const save = await function(catData,images){
console.log('catdata');
return callback({status:200,message:'test'});
}
} catch (e) {
console.log(e);
}
}
function uploadImages(images) {
//some stuff
return images;
}
Expected output : I want to return name of uploaded images from uploadImages function and pass it to another function to save in database.
Only async function returns promise.Make your uploadImages function async
async function uploadImages(images) {
//some stuff
return images;
}
The solution of Shubh Dixit works fine but i have to correct, that async functions do NOT return a real Promise but async function object. These do not have a .catch() or .finally() method. He is right, that a return inside a async function object will return a Promise.resolve()
async function x() {
return 2;
}
let value = await x();
returns a solved Promise with the value 2. Then the await returns the value of the resolved Promise to value. But if you try
let value = await x().catch((error)=> {console.log(error);});
you will recieve an error that .catch() is no method of x.

How to properly close a database connection when we return a Promise in NodeJS

I have two function like this:
async getMatches() {
try {
const result = await readRowsFromDb('SELECT * FROM matches');
console.log(result);
} catch (error) {
console.error(error);
}
}
async readRowsFromDb(query) {
const db = await sqlite.open(this.DATABASE_PATH);
const promise = db.all(query);
return promise;
}
getMatches();
The problem is I can't find a right place to put the line
db.close()
AFAIK, I should close the database after I get the result, but the result is in a different function, closing the db inside getMatches doesn't seem right.
I tried closing the database before returning the promise in readRowsFromDb like this
const promise = db.all(query);
db.close();
return promise;
It worked. But I still feel something wrong about it since I close the database connection right after the query is call instead of wait for it to finish, it shouldn't have worked.
Please advice.
If you want readRowsFromDb() to manage the opening and closing of the db (which it kind of has to because nobody else has the db object that you just opened), you can do that this way:
async readRowsFromDb(query) {
let db;
try {
db = await sqlite.open(this.DATABASE_PATH);
let result = await db.all(query);
return result;
} finally {
if (db) db.close();
}
}
Keep in mind that because this is an async function, it is still returning a promise that resolves to the result even though you aren't directly returning a promise yourself. That's how async functions work.
The only other way that you could close the db in another function is if you either passed in the db from some other function (so it could manage closing it) or if you returned the db from this function so someone else could use it before closing it. As your readRowsFromDb() function stands now, you have to close it in the function.
make db as a global variable and access it from getMatches;
let db;
async getMatches() {
try {
const result = await readRowsFromDb('SELECT * FROM matches');
console.log(result);
return result
} catch (error) {
console.error(error);
return error
}
}
async readRowsFromDb(query) {
db = await sqlite.open(this.DATABASE_PATH);
const promise = db.all(query);
return promise;
}
getMatches().then((resp) => {
db.close();
})

Fetching return value from async function

I am trying to capture the response of two service calls within a function. Got to know that async and await will solve this purpose and tried below. Here inside async function ex - I am making a call to users, companies end point and console log is displaying perfect, but while retrieving the same value by calling the async function is giving Promise Pending. I tried two options 1. by simply calling the async function - giving Promise Pending 2. by calling with await prefixed - giving await is a reserved word.
Please let me know how to capture the response from this...
const service = {
getUsers: () => axios.get(`http://localhost:3000/users`),
getCompanies: () => axios.get('http://localhost:3000/companies')
};
let ex = async () => {
let users = {};
let companies = {};
try {
users = await service.getUsers()
companies = await service.getCompanies()
console.log('Example ', {
users: users.data,
companies: companies.data
})
} catch (err) {
console.log(err);
}
return [{ users, companies}];
};
//let resp = await ex(); - giving await is a reserved word
// let resp = ex(); - giving Promise is pending..
console.log(resp);
All async functions will always return a promise. If you return nothing, the function will return a promise for undefined. Whatever you return will get wrapped up in a promise, which you need to await or call then on to access the value inside.
resp.then(console.log)

Categories