-4

I have a function that looks like

async function longPoll() {
    let timeout = 0
    try {
        // perform longPoll tasks
        let response = await axios.get(config.url)
        const data = response.data && response.data.data
        if (!Array.isArray(data)) {
            return
        }
        await Promise.all(data.map(async(item) => {
            try {
                // send message via WhatsApp using 'whatsapp-web.js'
                let chatId = getChatId(item)
                let text = getText(item)
                await client.sendMessage(chatId, text)
            } catch (e) {
                // some logging
                return
            }
            try {
                // report sending is ok
                let response = await axios.get(config.confirmationUrl)
            } catch (e) {
                // some logging
            }
        }))
    } catch (e) {
        if (e.response) {
            let status = e.response.status
            let statusText = e.response.statusText
            console.error(`Server response ${status} ${statusText}`)
        } else if (e.request) {
            console.error('No response from server.')
        } else {
            console.error('Failed to create request.')
        }
        timeout = 5000
    } finally {
        setTimeout(longPoll, timeout)
    }
}

longPoll() // kick off

In the beginning, it runs fine. After a while, longPoll() is no longer called. Why is it so?

I'm using NodeJS v16.14.0 with axios v0.19


Notes:

  1. I have found the cause. See my own answer.
  2. Repro steps available in my comment
  3. I undeleted this question for informational & sharing purpose
Afriza N. Arief
  • 7,696
  • 5
  • 47
  • 74
  • Please provide a [mcve]. Replace `axios.get(config.url)` with actual data, e.g. https://jsfiddle.net/wg9zr1jv/ – jabaa Mar 02 '22 at 16:48
  • @jabaa It will take some time before I can get minimal repro example then. – Afriza N. Arief Mar 02 '22 at 17:33
  • I guess you should delete this question and undelete it after you added a [mcve]. You could also ask a new question, but someone told me it's bad and I forgot the reason. Keep in mind to post a minimal example, not your whole code base. – jabaa Mar 02 '22 at 17:36
  • I’m voting to close this question because the problem was caused by occasional network issues and is not reproducible. – jabaa Jul 01 '22 at 07:03
  • Um, are you saying that handling "occasional network issues" is not relevant programming problem and thus this question is not fit for stackoverflow? It took me a few days (or weeks, I forgot) to figure it out and I personally think this is useful to others who might face similar issues; and decided to undelete it despite having many downvotes (which is bad for my image). – Afriza N. Arief Jul 01 '22 at 07:13
  • You didn't read my comment to the end. I'm saying that this is not reproducible. It's a typo-like problem. – jabaa Jul 01 '22 at 08:12
  • Actually, now that I know what the problem is.. I can provide you a repro steps: (1) a computer with the app connected to LAN port of a router with internet access on the WAN port; (2) setup a long-poll endpoint in the internet and start a request to it with, say, 30 secs long-poll duration; (3) before end of 30 secs, unplug WAN port of the router; (4) you should be able observe the behaviour. It sure is a typo-like problem if you consider "not knowing that I should put `{timeout: 25000}` into axios API calls" a typo. Sorry I sound rude even though you've been very polite in your comments. – Afriza N. Arief Jul 01 '22 at 10:04
  • To reproduce the problem, the nat setting of the router may need to be set to `srcnat` instead of `masquerade` to avoid connection table being reset. `srcnat` is the setting used in our actual router. – Afriza N. Arief Jul 01 '22 at 13:02

2 Answers2

0

The problem was caused by occasional network issues.

I solved it by

  1. Adding a timeout to axios calls; for example: axios.get(url, {timeout: 18000}) for 18 seconds timeout. This is the main solution.
  2. Keeping a timestamp of when the last http request was started and check it regularly with setInterval(). If it was not tolerable, I starts a new "loop". And also add handling if the number of long polling "loop" is too many and terminate the extra. I did this when I haven't found the culprit.

Based on my observation, the actual time spent before exception is thrown might be several seconds (up to 5 seconds) longer than timeout duration given to axios.

Afriza N. Arief
  • 7,696
  • 5
  • 47
  • 74
-3

The timeout calling the longpoll function is inside longpoll itself.
If you want to call a timeout on a function, the timeout must be outside of that function.

John Obla
  • 53
  • 1
  • 5