There are two approaches that come to my mind for this. A batch processing and a sliding window approach. Batch processing might be easier but using a sliding window will be the more efficient implementation.
Batch processing with Promise.all()
This approach creates batches of requests up to a specified batchSize and only after all requests in a batch are done, the next batch of requests is issued.
You need to add some error handling in case of failed requests here.
import fetch from "node-fetch";
// list of items that you might want to use to compose your URL (not actually used here)
let itemObject = [
{ itemName: "", itemID: "" },
{ itemName: "", itemID: "" },
{ itemName: "", itemID: "" },
{ itemName: "", itemID: "" },
{ itemName: "", itemID: "" },
{ itemName: "", itemID: "" },
{ itemName: "", itemID: "" },
{ itemName: "", itemID: "" },
{ itemName: "", itemID: "" },
{ itemName: "", itemID: "" },
{ itemName: "", itemID: "" },
{ itemName: "", itemID: "" },
];
(async () => {
// number of concurrent requests in one batch
const batchSize = 4;
// request counter
let curReq = 0;
// as long as there are items in the list continue to form batches
while (curReq < itemObject.length) {
// a batch is either limited by the batch size or it is smaller than the batch size when there are less items required
const end = itemObject.length < curReq + batchSize ? itemObject.length: curReq + batchSize;
// we know the number of concurrent request so reserve memory for this
const concurrentReq = new Array(batchSize);
// issue one request for each item in the batch
for (let index = curReq; index < end; index++) {
concurrentReq.push(fetch("https://postman-echo.com/get"))
console.log(`sending request ${curReq}...`)
curReq++;
}
// wait until all promises are done or one promise is rejected
await Promise.all(concurrentReq);
console.log(`requests ${curReq - batchSize}-${curReq} done.`)
}
})();
Expected result:
sending request 0...
sending request 1...
sending request 2...
sending request 3...
requests 0-4 done.
sending request 4...
sending request 5...
sending request 6...
sending request 7...
requests 4-8 done.
sending request 8...
sending request 9...
sending request 10...
sending request 11...
requests 8-12 done.
Sliding window with semaphore
This approach uses a sliding window and schedules a new request as soon as another request is done while always keeping the request count below or equal to a maximum number of n concurrent requests at any one time.
What you need to implement this is a Semaphore.
There is a library for this in JavaScript called async-mutex.
Here a sample program using this library to send 2 requests concurrently to the Postman Echo API. There will never be more requests running concurrently as the semaphore allows for (in your case that limit would be 5, here it's 2).
import { Semaphore } from "async-mutex";
import fetch from "node-fetch";
// list of items that you might want to use to compose your URL (not actually used here)
let itemObject = [
{ itemName: "", itemID: "" },
{ itemName: "", itemID: "" },
{ itemName: "", itemID: "" },
{ itemName: "", itemID: "" },
{ itemName: "", itemID: "" },
{ itemName: "", itemID: "" },
{ itemName: "", itemID: "" },
{ itemName: "", itemID: "" },
{ itemName: "", itemID: "" },
{ itemName: "", itemID: "" },
{ itemName: "", itemID: "" },
{ itemName: "", itemID: "" },
];
(async () => {
// allow two concurrent requests (adjust for however many are required)
const semaphore = new Semaphore(2);
itemObject.forEach(async (item, idx) => {
// acquire the semaphore
const [value, release] = await semaphore.acquire();
// at this point the semaphore has been acquired and the job needs to be done
try {
console.log(`sending request ${idx}...`)
const response = await fetch("https://postman-echo.com/get")
if(!response.ok){
console.log(`request failed with status code ${response.status}`)
}
}
catch (error) {
console.log("request failed.")
}
finally {
console.log(`request ${idx} done...`)
// release the semaphore again so a new request can be issued
release();
}
})
})();
Expected output (order may vary):
sending request 0...
sending request 1...
request 1 done...
sending request 2...
request 2 done...
sending request 3...
request 3 done...
sending request 4...
request 0 done...
sending request 5...
request 4 done...
sending request 6...
request 5 done...
sending request 7...
request 6 done...
sending request 8...
request 7 done...
sending request 9...
request 8 done...
sending request 10...
request 9 done...
sending request 11...
request 10 done...
request 11 done...