'For loop not being itereated properly with promises
I've being converting a project from Javascript to Typescript and encountered some problems when running a retry on fail system. This system works fine on vanilla JS but it seems to fail somewhere on Typescript.
var t: number = 500;
var max: number = 5;
const rejectDelay = (reason: string): Promise<any> => {
return new Promise((resolve, reject) => {
log.warn('Unable to connect to database. Trying again...');
setTimeout(() => reject.bind(null, reason), t);
});
};
const dbConn = async (): Promise<void> => {
let conn = await db.pool
.getConnection()
.then((message: any) => {
if (!message.isValid()) {
throw message.isValid;
} else {
return message.isValid;
}
});
};
const connected = (res: string): void => {
log.info('Connection to database is successful.');
log.info(`App is running in port ${envs.port} in ${envs.mode} mode.`);
};
const notConnected = async (err: any): Promise<void> => {
log.error('Max attempts exceeded, app will exit...');
process.exit(1);
};
var p: Promise<any> = Promise.resolve();
for (var i = 0; i < max; i++) {
console.log(i);
p = p.catch(dbConn).catch(rejectDelay);
}
p = p.then(connected).catch(notConnected);
after running the project this is expected result:
[info] 2022-05-18 01:13:03: Router users registered...
[info] 2022-05-18 01:13:03: Router utils registered...
0
[warn] 2022-05-18 01:12:59: Unable to connect to database. Trying again...
1
[warn] 2022-05-18 01:12:59: Unable to connect to database. Trying again
2
[warn] 2022-05-18 01:12:59: Unable to connect to database. Trying again
3
[warn] 2022-05-18 01:12:59: Unable to connect to database. Trying again
4
[error] 2022-05-18 01:13:44: Max attempts exceeded, app will exit...
and this is what I get:
[info] 2022-05-18 01:13:03: Router users registered...
[info] 2022-05-18 01:13:03: Router utils registered...
0
1
2
3
4
[error] 2022-05-18 01:13:44: Max attempts exceeded, app will exit...
Any suggestions?
Solution 1:[1]
If you want it to stop on the first connection and you want it to wait a timeout before trying again upon a connection failure, then you need a different approach. Here's one way to do it (note you may have to fix up some TypeScript stuff as I'm a plain JS developer, not TypeScript):
const t: number = 500;
const max: number = 5;
const rejectDelay = (reason: string): Promise<any> => {
return new Promise((resolve, reject) => {
log.warn('Unable to connect to database. Trying again...');
setTimeout(resolve, t, reason);
});
};
const dbConn = async (): Promise<void> => {
const conn = await db.pool.getConnection();
if (!conn.isValid()) {
throw message.isValid;
}
return conn;
};
const connected = (res: string): void => {
log.info('Connection to database is successful.');
log.info(`App is running in port ${envs.port} in ${envs.mode} mode.`);
};
const notConnected = async (err: any): Promise<void> => {
log.error('Max attempts exceeded, app will exit...');
process.exit(1);
};
async function getConn() {
for (let i = 0; i < max; i++) {
try {
console.log(i);
let conn = await dbConn();
return conn;
} catch(e) {
await rejectDelay(e);
}
}
throw new Error("database connection failed, all retries used");
}
getConn().then(result => {
connected(result);
}).catch(err => {
notConnected(err);
});
To attempt to debug this myself, I added a bunch of debugging and made it so it would run stand-alone in nodejs. You can copy this to a separate file and run it by itself and see how it works. I've made dbConn() such that it fails the first 3 times, then succeeds the fourth time so you can see how it works:
const t = 500;
const max = 5;
function delay(t, v) {
return new Promise(resolve => setTimeout(resolve, t, v));
}
// simulate db.pool.getConnection()
// fails first 3 times, succeeds after that
const db = {
pool: {
async getConnection() {
await delay(500);
++db.pool.cntr;
if (db.pool.cntr <= 3) {
throw new Error("Can't connect to Database");
} else {
return { connected: true, isValid: () => true };
}
},
cntr: 0
}
}
// simulate log.info() and log.error
const log = {
info(...args) {
console.log(...args);
},
error(...args) {
console.log(...args);
},
warn(...args) {
console.log(...args);
}
}
// simulate envs
const envs = {
port: 3000,
mode: "development"
}
const rejectDelay = (reason) => {
return new Promise((resolve, reject) => {
log.warn('Unable to connect to database. Trying again...');
setTimeout(resolve, t, reason);
});
};
const dbConn = async () => {
const conn = await db.pool.getConnection();
if (!conn.isValid()) {
throw message.isValid;
}
return conn;
};
const connected = (res) => {
log.info('Connection to database is successful.');
log.info(`App is running in port ${envs.port} in ${envs.mode} mode.`);
};
const notConnected = async (err) => {
log.error('Max attempts exceeded, app will exit...');
process.exit(1);
};
async function getConn() {
for (let i = 0; i < max; i++) {
try {
console.log(i);
let conn = await dbConn();
console.log(i, "after");
return conn;
} catch (e) {
console.log(i, "catch");
await rejectDelay(e);
console.log(i, "after rejectDelay");
}
}
throw new Error("database connection failed, all retries used");
}
getConn().then(result => {
connected(result);
}).catch(err => {
notConnected(err);
});
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |
