Search code examples
node.jsrecursionasync-awaitfetchsettimeout

How to set timeout with abort controller and retry in ES7 async await function


I am trying fetch request, if request takes time longer than specified timeout then I am aborting it using abort controller or if there is error in response like socket hangup then try to fetch it again recursively. I want to repeat it i.e 5 times and in last if it fails then return just error. But in my code after 1st try it fails instantly and shows fetch request aborted. Here is my code. Thank you in advance.

const getData = async () => {
  let url = `https://www.example.com`
  let options = {
    method: 'POST',
    agent: proxyagent,
    signal: signal,
    body: JSON.stringify({
      username: 'abc'
    })
  }
  const fetchData = async (retries) => {
    try {
      let timer = setTimeout(() => controller.abort(), 1000)
      let response = await fetch(url, options)
      clearTimeout(timer)
      if (response.ok) return response.json()
    } catch (e) {
      console.log(e)
      if (retries === 1 || retries < 1) {
        return {
          message: 'Something went wrong'
        }
      }
      return await fetchData(retries - 1)
    }
  }
  return await fetchData(5)
}

Solution

  • You cannot reuse an aborted signal. You will have to create a new one for each fetch

    const getData = async () => {
      let url = `https://www.example.com`;
      let controller;
      let options = {
        method: 'POST',
        agent: proxyagent,
        body: JSON.stringify({
          username: 'abc'
        })
      }
      const fetchData = async (retries) => {
        controller = new AbortController();
        const optionsWithSignal = {
          ...options,
          signal: controller.signal
        };
    
        try {
          let timer = setTimeout(() => controller.abort(), 1000)
          let response = await fetch(url, optionsWithSignal)
          clearTimeout(timer);
          if (response.ok) return response.json()
        } catch (e) {
          console.log(e)
          if (retries === 1 || retries < 1) {
            return {
              message: 'Something went wrong'
            }
          }
          return await fetchData(retries - 1)
        }
      }
      return await fetchData(5)
    }