Home > other >  Add retry function in fetch API
Add retry function in fetch API

Time:01-05

The main objective is to Implement a re-try functionality if the screen is frozen. If the API call to save the test fails, then the code will re-try at least 3 times.

I want to add a retry function in a fetch the API but had an output of a bad request in the console. Also, I don't know if I have the correct placement of the action to invoke the srfl_save_response action. Can someone help me? This is the code below:

function fetchWithAutoRetry(fetcher,maxRetryCount){

            return new Promise((resolve,reject) => {

            let retries=0;

            const caller= () => fetcher(  
                jQuery(document).trigger('srfl_save_response', [ question_id, question_index, question_type, question_response ])   
            )
                .then((data)=> {
                    resolve(data);
            })
            .catch((error) => {
              if(retries < maxRetryCount){
                retries  ;
                caller();
                }else{
                reject(error);
            }
        });
            retries=1;
            caller();
        });
        }

const fetchAdminAjax = async () => {
  fetch("https://test.tutorials.com/wp-admin/admin-ajax.php", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      question_id,
      question_index,
      question_type,
      question_response,
    }),
  })
    .then((res) => res.json())
    .then((data) => console.log(data))
    .catch((error) => console.error(error));
  //    const jsonResponse = await rawResponse.json();
  //        return jsonResponse;
  //        console.log(rawResponse);
};

fetchWithAutoRetry(fetchAdminAjax, 3);

I tried using let in fetch but still bad request

CodePudding user response:

You can use a simple, async for loop.

For example

const asyncAutoRetry = async (asyncFn, limit) => {
  for (let i = 0; i < limit; i  ) {
    try {
      return await asyncFn();
    } catch (err) {
      console.warn("Failed attempt", i   1, err);
    }
  }

  throw new Error(`${limit} max attempts reached`);
};

const asyncAutoRetry = async (asyncFn, limit) => {
  for (let i = 0; i < limit; i  ) {
    try {
      return await asyncFn();
    } catch (err) {
      console.warn("Failed attempt", i   1, err);
    }
  }

  throw new Error(`${limit} max attempts reached`);
};

const fakeFetch = (succeedAfter) => {
  let attempt = 0;
  return () => new Promise((resolve, reject) => {
    if (  attempt > succeedAfter) {
      return resolve("Done");
    }
    reject("Failed fetch");
  });
};

asyncAutoRetry(fakeFetch(2), 3).then(console.log).catch(console.error);

You just need to ensure that your requests fail properly

// Handy wrapper to check for unsuccessful responses and return JSON
const fetchWrapper = async (url, init = {}) => {
  const res = await fetch(url, init);
  if (!res.ok) {
    const err = new Error(`${res.status} ${res.statusText}`);
    err.text = await res.text();
    throw err;
  }
  return res.json();
};

asyncAutoRetry(
  () =>
    fetchWrapper("https://staging.tutorialsdojo.com/wp-admin/admin-ajax.php", {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        question_id,
        question_index,
        question_type,
        question_response,
      }),
    }),
  3
)
  .then(console.log)
  .catch(console.error);

CodePudding user response:

Normally I would ensapsulate fetch call in another method, let's say that is retryFetch, then in that method you can define the fetch call recursively with number of retries, delays etc. Those attributes can be passed via parameters.

retryFetch(url, retries = 5, interval = 1000, options = {}) 

So this retryFetch function could be like this, notice if error occurs the same function is being invoked in the specified interval until all retry count is exhausted.

private wait(delay) {
        return new Promise((resolve) => setTimeout(resolve, delay));
} 

private retryFetch(url, delay = 1000, tries = 3, fetchOptions = {}) {
        let that = this; 
        function one rror(err) {
            let triesLeft = tries - 1;
            if (!triesLeft) {
                console.log(`err after retry ${triesLeft} api - `   err);
                throw err;
            }
            return that.wait(delay).then(() => that.retryFetch(url, delay, triesLeft, fetchOptions));   <--------------------- Note here
        }
        function handleErrors(response) {
            if (!response.ok) {
                throw Error(response.statusText);
            }
            return response;
        }
        return fetch(url, fetchOptions).then(handleErrors).catch(onError);
}

Now you can call it.

const body: string = JSON.stringify({
      question_id,
      question_index,
      question_type,
      question_response,
    }),

let serviceResponse = this.retryFetch("https://staging.tutorialsdojo.com/wp-admin/admin-ajax.php", 1000, 3
            , {
                headers: {
                   "Content-Type": "application/json",
                },
                body: body
              }
        );

let finalData = (await serviceResponse).json();
  • Related