caolan / async

Async utilities for node and the browser
http://caolan.github.io/async/
MIT License
28.18k stars 2.41k forks source link

async.mapLimit() finishes but wont trigger last callback. #1760

Closed abobakrd closed 2 years ago

abobakrd commented 3 years ago

What version of async are you using? 3.2.0

Which environment did the issue occur in (Node/browser/Babel/Typescript version) Node

What did you do? Please include a minimal reproducible case illustrating issue. I'm trying to do work on ~10k items through a Promise chain whereas the work is done in 50 async iterations at the same time.

The code snippet is just meant to illustrate the code flow and does not include all original code. The promise chain is designed in a way that catch() at the end is always called so the callback function (cb) for the current async iteration gets called.

let asyncIterationsDoneCount = 0; // used for logging the async process
async.mapLimit(urlList, 50, (url, cb) => { 
    asyncIterationsDoneCount++;

    // promise chain
    DoRequest(url) 
        .then(r => DoMoreWithUrl())
        .then(r => {
             throw new Error('done'); // terminates the chain and triggers catch()

        }).catch(err => { 
            console.log('async op finished, results/err: ', err);
            console.log(urlList.length - asyncIterationsDoneCount, ' async iterations left');
            cb(null, err); // end current async iteration
        }
}, (err, results) => {
        if(err)
          thow new Error(err);

        console.log('All async operations finished, results: ', results);
});

What did you expect to happen? The last callback in async.mapLimit function to fire, to signal it's done with all async iterations. It fires when urlList is below ~3000 in length, but above this, no.

What was the actual result? The log from the program outputs this while hanging forever: 0 async iterations left. When i run the program in the terminal (node program.js) it's impossible to exit the node program with ctrl + c in the terminal (linux), so i must kill the process eventually.

aearly commented 3 years ago

Going to need an executable code example here.

However, I will say that throwing an error and using .catch() to signal the end of a promise chain is a bit odd. Why doesn't .then() work?

abobakrd commented 3 years ago

The source code that uses the promise chain is pretty large, so I just included a pseudo example that replicates the exact same source code algorithm. The chain works well on lists with length of items under ~5000, but above this it starts to hang. Regarding the chain terminator method, I've used catch() for faster processing of a failed chain, otherwise I'd have to conditionally check every result within each then() to be eligible for ending the current async operation with firing the cb callback function. It works, but may be a bit odd-looking from a design perspective.

Not sure what happened but the code works sometimes now with items length over ~10k.