Skip to content Skip to sidebar Skip to footer

Fetch Retry Request (on Failure)

I'm using browser's native fetch API for network requests. Also I am using the whatwg-fetch polyfill for unsupported browsers. However I need to retry in case the request fails. N

Solution 1:

From the fetch docs :

fetch('/users')
    .then(checkStatus)
    .then(parseJSON)
    .then(function(data) {
          console.log('succeeded', data)
    }).catch(function(error) {
          console.log('request failed', error)
    })

See that catch? Will trigger when fetch fails, you can fetch again there. Have a look at the Promise API.

Implementation example:

functionwait(delay){
    returnnewPromise((resolve) =>setTimeout(resolve, delay));
}

functionfetchRetry(url, delay, tries, fetchOptions = {}) {
    functiononError(err){
        triesLeft = tries - 1;
        if(!triesLeft){
            throw err;
        }
        returnwait(delay).then(() =>fetchRetry(url, delay, triesLeft, fetchOptions));
    }
    returnfetch(url,fetchOptions).catch(onError);
}

Edit 1: as suggested by golopot, p-retry is a nice option.

Edit 2: simplified example code.

Solution 2:

I recommend using some library for promise retry, for example p-retry.

Example:

const pRetry = require('p-retry')
const fetch = require('node-fetch')

asyncfunctionfetchPage () {
  const response = awaitfetch('https://stackoverflow.com')

  // Abort retrying if the resource doesn't existif (response.status === 404) {
    thrownew pRetry.AbortError(response.statusText)
  }

  return response.blob()
}

;(async () => {
  console.log(awaitpRetry(fetchPage, {retries: 5}))
})()

Solution 3:

I don't like recursion unless is really necessary. And managing an exploding number of dependencies is also an issue. Here is another alternative in typescript. Which is easy to translate to javascript.

interface retryPromiseOptions<T>  {
    retryIf?:(response:T) =>boolean, 
    retries?:number
}

function retryPromise<T>(promise:() =>Promise<T>, options:retryPromiseOptions<T>) {
    const { retryIf = (_:T) =>false, retries = 1} = options
    let _promise = promise();

    for (var i = 0; i < retries; i++)
        _promise = _promise.then((value) =>retryIf(value) ? promise() : Promise.reject(value));
    
    return _promise;
}

And use it this way...

retryPromise(fetch(url),{
    retryIf: (response:Response) =>true, // you could check before trying againretries: 5
}).then( ... my favorite things ... )

I wrote this for the fetch API on the browser. Which does not issue a reject on a 500. And did I did not implement a wait. But, more importantly, the code shows how to use composition with promises to avoid recursion.

Post a Comment for "Fetch Retry Request (on Failure)"