skip to Main Content

I need to make a variable amount of requests. Could be 2, could be 305. The server that the requests are made to runs on 10 threads, so it can handle 10 requests at a time. I predict that if I make all of them at the same time, the last ones will time out because the server is taking too long handling them all.

What I want to do is make them in batches of 10 to avoid this. However, because JS is async, a simple loop with 10 requests won’t work because they all will be made in one go anyway.

So what I’m searching for is a way to make a "group" of requests, wait until all of them have completed, and then continue on to the next group. I haven’t found a way to achieve this, so any help would be appreciated 🙂

2

Answers


  1. What you’re looking for is a semaphore. There’s a package for javascript called async-mutex that can handle most of the setup you’ll need. You can set it up to allow a limited amount of processes access to a resource at once, which should let you batch your requests.

    You can combine this with async functions to allow you to use promises if you need them to be synchronous.

    Without code I don’t know what your implementation would look like, but you could do something like:

    const Semaphore = require('async-mutex');
    const semaphore = new Semaphore(10);
    
    async function main() {
       await semaphore.acquire()
       // your request code here
    }
    

    Which would limit you to 10 requests at a time, no matter how many are waiting in the queue.

    Login or Signup to reply.
  2. Usually, you want to use resources most efficiently, and in this case it makes sense to not work in batches, but just limit number of active requests. So once request finishes new one is made. Blake’s answer describes how to achieve that using semaphore.

    If you need to process data precisely in batches (i.e. wait for all requests from batch to complete before starting new one) you can use function like this:

    async function executeInBatches(data, factory, batchSize = 10) {
        // Make a copy of original array as we'll modify it
        const queue = [...data];
        let promises = [];
        const results = [];
        while (queue.length > 0) {
            // Take batchSize number of items from queue (or all remaining items if smaller than batchSize)
            const batchToProcess = queue.splice(0, Math.min(batchSize, queue.length));
            // Call factory for each value to get a promise
            promises = batchToProcess.map(val => factory(val));
            // Wait for all promises to finish before starting another batch
            const batchResults = await Promise.all(promises);
            results.push(...batchResults);
        }
    
        return results;
    }
    
    // Example ussage:
    
    function makeRequest(url) {
        return fetch(url).then(r => r.text());
    }
    
    const urls = [
        'http://example.com/1',
        'http://example.com/2',
        'http://example.com/3',
        // Long list of urls....
    ];
    
    executeInBatches(urls, makeRequest).then((results) => {
        console.log('Loaded all urls', results);
    });
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search