-1

I have scheduler that calls api urls every minute (totally 3 api urls) the problem is instead of calling 3 urls every minute it calls those 3 urls continuously and so i could end up calling those 3 urls 50 times or more each minute.

My question is how to avoid those extra calls?

My code sample: commented for better understanding

// adding sleep between api calls
function sleep(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}

// call for apis every minutes
cron.schedule("* */1 * * * *", () => {
    // total of 3 url addresses (so every minute call 3 urls)
    addresses.forEach(async (address) => {
        await sleep(3000);
        await showTransactionMessage(id, userName, address);
    });
});

// get api data and call message function to send message
async function showTransactionMessage(id, userName, address) {
    await axios.get(address).then(async (response) => {
        if ( response.data.result && Array.isArray( response.data.result ) ) {
            response.data.result.map(async (item) => {
                //start
                const start = async () => {                      
                    await asyncForEach(
                        time = new Date(parseInt(item.timeStamp * 1000)).toLocaleString().split(", ")[1],
                        date = new Date(parseInt(item.timeStamp * 1000)).toISOString().slice(0, 10).split('-').join('/'),
                        timestamp = item.timeStamp,
                        hash = item.hash,
                        from = item.from,
                        to = item.to,
                        value = item.value.toString().slice(0, '-' + item.tokenDecimal),
                        userName,
                    async (response) => {
                        bot.sendMessage(id, response, keyboard);
                    });
                    console.log('Done');
                };
                await sleep(6000); //every 6 seconds send 1 message
                start();
                //end
            });
            console.log('address: ', address); // sample result, below
        } else { 
            console.log('Got issue with response array.');
        }
    }).catch((err) => {
        console.log('error1', err)
    });
};

// send message by api data provided from `showTransactionMessage` fiunction
async function asyncForEach(time, date, timestamp, hash, from, to, value, userName, callback) {
    let response = "";
    response += 'Date: '+date+'\n';
    response += 'Time: '+time+'\n';
    response += 'TX: '+hash+'\n';
    response += 'Receiver: '+to+'\n';
    await callback(response);
}

What I end up with code above is

address:  address 1
address:  address 3
address:  address 1
address:  address 2
address:  address 2
address:  address 3
address:  address 1
address:  address 3
address:  address 2
address:  address 1
address:  address 1

Instead of

address:  address 1
address:  address 2
address:  address 3

Any suggestions?

mafortis
  • 6,750
  • 23
  • 130
  • 288
  • The main problem is `forEach` not waiting for the promise that your callback returns. But you've also got the same problem with `response.data.result.map(…)` (which creates an array of promises that you ignore), you're not `await`ing `start()`, you're mixing `await` syntax with `.then()`/`.catch()` methods unnecessarily, and that `asyncForEach` call is total bullocks with the assignment expressions as arguments. – Bergi Apr 04 '22 at 03:07

1 Answers1

0

From what I know, forEach wouldn't wait on an async function and just simply runs it..
try using for(...){await ...} so maybe it might solve the problem

// adding sleep between api calls
function sleep(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}

// call for apis every minutes
cron.schedule("* */1 * * * *", async() => {
    // total of 3 url addresses (so every minute call 3 urls)
    for (let address of addresses) {
        await sleep(3000);
        await showTransactionMessage(id, userName, address);
    }
});

// get api data and call message function to send message
async function showTransactionMessage(id, userName, address) {
    //because if you're not waiting, what's the point of showTransactionMessage being async?
    try{var response = await axios.get(address);} //var scope perfect for this
    catch(err){return console.log('error1', err);} //return because no further action if this fails
    if ( response.data.result && Array.isArray( response.data.result ) ) {
        for (let item of response.data.result) {
            //start
            const start = async () => {                      
                await asyncForEach(
                    time = new Date(parseInt(item.timeStamp * 1000)).toLocaleString().split(", ")[1],
                    date = new Date(parseInt(item.timeStamp * 1000)).toISOString().slice(0, 10).split('-').join('/'),
                    timestamp = item.timeStamp,
                    hash = item.hash,
                    from = item.from,
                    to = item.to,
                    value = item.value.toString().slice(0, '-' + item.tokenDecimal),
                    userName,
                async (response) => { //because if you're not waiting, what's the point of callback being async?
                    await bot.sendMessage(id, response, keyboard);
                });
                console.log('Done');
            };
            await sleep(6000); //every 6 seconds send 1 message
            await start(); //why don't you wait for start to finish?
            //end
        }
        console.log('address: ', address); // sample result, below
    } else { 
        console.log('Got issue with response array.');
    }
};

// send message by api data provided from `showTransactionMessage` function
async function asyncForEach(time, date, timestamp, hash, from, to, value, userName, callback) {
    let response = "";
    response += 'Date: '+date+'\n';
    response += 'Time: '+time+'\n';
    response += 'TX: '+hash+'\n';
    response += 'Receiver: '+to+'\n';
    await callback(response);
}
The Bomb Squad
  • 4,192
  • 1
  • 9
  • 17
  • Thank you, I tried your code it never hits `console.log('address: ', address);` that supposed to return when each address data process in done right? so `url1 =done`, `url2=done`, `url3=done` then wait 1 minute and again`url1=done,....` – mafortis Apr 04 '22 at 03:24