Home > Software engineering >  Repeat failing promise for n times wrapper error in typescript
Repeat failing promise for n times wrapper error in typescript

Time:11-01

I have a wrapper that calls an async function:

function fetchAPI(arg1: number, arg2: number, arg3: string) {
  return new Promise((resolve, reject) => {
    try {
      myFetchFunction(arg1, arg2, arg3).then((r: any) => {
        if (!r) {
          reject("Error 01")
        }
        resolve(r)
      })
    } catch {
      reject("Error 01")
    }
  })
}

Since the API I am querying is quite unstable, it occurs frequently that the fetchAPI function rejects.

Because of this, I make another function that calls fetchAPI, if it rejects it will repeat the call at most 3 times (waiting 1s) and if it fails all the times it will just resolve with undefined. While if it goes through any of the 3 times, it will simply resolve with the correct response.

function fetchAPIRepeat(arg1: number, arg2: number, arg3: string, n: number = 0) {
  return new Promise((resolve) => {
    fetchAPI(arg1, arg2, arg3).then((r) => {
      resolve(r)
    }).catch(() => {
      if(n < 3) {
        console.log("Partial error: "   n)
        sleep(1000).then(() => {
          resolve(fetchAPIRepeat(arg1, arg2, arg3, n   1))
        })
      } else {
        resolve(undefined)
      }
    })
  })
}

This works perfectly fine. However, I would like to create a 'general wrapper' which would operate as the fetchAPIRepeat function, but for any promise function I pass it through.

This is what I have tried, however it doesn't work:

function promiseRepeatWrapper(fn: (...args: any[]) => Promise<any>, n: number = 0, ...args: any[]) {
  return new Promise((resolve) => {
    fn(args).then((r) => {
      resolve(r)
    }).catch(() => {
      if(n < 3) {
        console.log("Partial error: "   n)
        sleep(1000).then(() => {
          resolve(this.errorWrapper(fn, n   1, args))
        })
      } else {
        resolve(undefined)
      }
    })
  })
}

By 'doesn't work' I mean that the console logs the 'Partial error' for three times, and then resolves with undefined, despite being sure that the promise goes through correctly all three of the times:

Partial error: 0
Partial error: 1
Partial error: 2

Other than helping me fix the function, I am also interested in error-handling design improvements for my promise-repeat pattern.

Thanks.

CodePudding user response:

This can be achieved with async/await. You do not need to pass that args again. You can do it will a lot more generic approach. Where you can pass who many times to retry, and how much to wait after retry

Here is a typescript playgorund

const waitFor = (timeout: number): Promise<void> => {
    return new Promise((resolve) => {
        setTimeout(() => resolve(), timeout);
    });
}

async function retryPromise<T>(fn: () => Promise<T>, repeat = 3, retryAfter = 1000): Promise<T> {
    let currentAttpmt = 1;
    while(currentAttpmt <= 3) {
        try {
            return await fn();
        } catch (e) {
            currentAttpmt  = 1;
            await waitFor(retryAfter);
        }
    }

    //it failed 3 times in a row
    throw new Error("Cannot do this");
}
  • Related