NodeJS async.retry fetch not completing / freezes after fetch

Advertisements

I’m trying to benchmark a web-api, but it seems that the benchmark app doesn’t continue after the initial requests. When trying to run the code, doStressTest() starts normally, and starts to attempt to fetch data from the web-api, but doesn’t seem to return anything, probably either due to the fetch() call, something within the parallelLimit() function, or my incorrect usage of those two frameworks. This leads to the code not going further than the line await async.parallelLimit(promises, limit), thus freezing the app completely. The initial requests are received by the tested web-api and handled correctly by the web-api.

Why does the code freeze, and how to fix it?

Fetch request seems to return correctly if used otherwise, as for example running the following code snippet will print out "This completes normally"

fetch(`http://localhost:3000/users/1/cards`).then(() => {
    console.log("This completes normally");
});

How the benchmark is run for X fetches at once and where it freezes

import async from "async";
import fetch from "node-fetch";

const users = [];
for(let i = 1; i <= 5000; ++i) {
    users.push(i);
}

function attemptFetches(limit) {
    // construct all promises
    let promises = [...users].map((user) => {
        // THESE ARE THE REQUESTS async.parallelLimit WILL RUN
        return () => async.retry(1000000, () => fetch(`http://localhost:3000/users/${user}/cards`));
    });

    const promise = new Promise(async (resolve, reject) => {
        const startTime = performance.now();
        // CODE RUNS UNTIL the line below \/
        await async.parallelLimit(promises, limit);
        // DOESN'T CONTINUE FROM HERE ON OUT
        const endTime = performance.now();
        resolve(endTime - startTime);
    });

    return promise;
}

How the stresstest is initiated

async function doStressTest() {
    result = await attemptFetches(10);
    console.log(`Running ${users.length} fetch queries in sets of 10 took ${result} ms`);
    result = await attemptFetches(100);
    console.log(`Running ${users.length} fetch queries in sets of 100 took ${result} ms`);
    result = await attemptFetches(1000);
    console.log(`Running ${users.length} fetch queries in sets of 1000 took ${result} ms`);
    result = await attemptFetches(5000);
    console.log(`Running ${users.length} fetch queries in sets of 5000 took ${result} ms`);
};

const i = setInterval(() => {
    // prevent node from killing process
}, 1000);

doStressTest().then(() => {
    clearInterval(i);
});

used npm package documentations:
async.parallelLimit, async.retry, node-fetch

>Solution :

This line is returning non-async functions:

return () => async.retry(1000000, () => fetch(`http://localhost:3000/users/${user}/cards`));

Therefore your await calls in doStressTest() don’t know to actually await anything as it’s not returning promises.

If you add an async to each of your anonymous functions then it will work correctly:

return async () => async.retry(1000000, async () => fetch(`http://localhost:3000/users/${user}/cards`));

Leave a ReplyCancel reply