I am trying to force a rejection for a promise.allSettled()
function in a controlled way.
The idea is run a series of urls in batches through an API, this api from time to time returns a 500 error for a given request and can safetly be retried. So I want to trigger a rejection on promise.allSettled()
where I can collect the failing urls and later on rerun on a recursion.
Batchrequest function
export async function batchRequest(poolLimit, array, iteratorFn, exception) {
const promises = []
const racers = new Set()
for (const item of array) {
const pro = Promise.resolve().then(() => iteratorFn(item, array))
promises.push(pro)
racers.add(pro)
const clean = () => racers.delete(pro)
pro.then(clean).catch(clean)
if (racers.size >= poolLimit) await Promise.race(racers)
}
const results = await Promise.allSettled(promises)
// Collect errors rejected by iteratorFn,
const rejected = results
.filter(({ status, reason }) => status === 'rejected' && reason.name === exception)
.map(({ reason }) => reason.error)
// Recurse the array of rejected urls
if (rejected.length) {
await batchRequest(poolLimit, rejected, iteratorFn, exception)
}
}
Here we run the promises as normal but collect all rejected urls, I am trying to use the exception
'timeout' as the rule to determine if it needs to be rerun as it was just a timeout error.
Iterator function
async function runRequest(url) {
try {
const { data } = await axios('https://exampleAPI.com')
// Take the data and write it somewhere...
} catch (error) {
if (error.response.status === 500) {
throw { name: 'timeout', url }
}
}
})
const urls = [...many urls]
await batchRequest(100, urls, runRequest, 'timeout')
I am getting an error saying
This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). The promise rejected with the reason "#<Object>".] { code: 'ERR_UNHANDLED_REJECTION' }
How can I force a controlled rejection on promise.allSettled()
?
UPDATE-----
I found that the unhandled rejection was at the point in which I started the batchrequest
await batchRequest(100, urls, runRequest, 'timeout')
I needs a try catch there, but the whole point was to use the promise.allSettled()
to absorb the error and not get out of the batchrequest
CodePudding user response:
It looks to me like you're not handling the exception thrown by the runRequest
or the first call to iteratorFn
. That's what's causing the "unhandled exception" error.
I'd suggest to run this code through a debugger and go line by line until you find the line causing you to get that exception thrown.
CodePudding user response:
Just manually handle each promise and collect errors and results and return or throw when all promises resolved:
const errors = [];
const results = [];
Promise.all(
promises.map(p => p.then(r => results.push(r)).catch(e => errors.push(e))
).then(() => {
if (errors.length) throw errors;
return results;
});