How to handle app.request promises together with retries and make it work with Promise.allSettled?

Handling app.request promises together with retries gives me error

I have three app.requests calls that needs to run async and need to wait for all to finish first and it does not matter if some reject and other are fulfilled I use this info to show something to the user if one of them is rejected!

But when I add retry to the app.request calls “reject” gives me an error in the console and then the Promise.allSettled is not showing the final response and it get

Unhandled promise rejection... Error: could't get user profile!

If I do not use retries in the app.request calls then Promise.allSettled response works again!

any ideas how to fix this?

In my case, I need to do retries in my app.request calls because amazon AWS services api gateway sometimes gives 500 error bad gateway when busy or connection is not stable and need to retry a second or third time.

here the code:

The method to call getProfile to get user profile with retries maximum of 3 times. the other two app.request methods self.getPreferences(), self.getStores() has the same code structure like this one below but with different urlPath…

      getProfile: function (retries = 3, backoff = 300) {

        var self = this;
        var app = self.$app;
        var $ = self.$$;

        console.log('user profile...');
        urlPath = "api_url_01";

        const retryCodes = [408, 500, 502, 503, 504, 522, 524, 400];

        return new Promise(function (resolve, reject) {

            app.request.promise({
              headers: {
                'Content-Type': 'application/json',
              },
              url: urlPath1,
              dataType: 'json',
              async: true,
              method: 'GET',
              data: {},
              cache: false,
              crossDomain: true,
            }).then(function (res) {

              /* handle the successful result */
              resolve(res);

            }).catch(function (err) {

              /* handle the error */ 
              console.log(err);

              const { status } = err;

              console.log({statusCode: status});

                if (retries > 0 && retryCodes.includes(status)) {
    
                  setTimeout(() => {
                    return self.getProfile(retries - 1, backoff * 2) 
                  }, backoff);

                } else {
 
                  reject(new Error("could't get user profile!"));

                }
              
            });

          }).finally(function () {

            /* hide the preloader */
            console.log("handle finally...");

          });

      },

The init method to init all requests…

initRequests: function (e) {

const thisPromises = [self.getProfile(), self.getPreferences(), self.getStores()];

var eachPromises = thisPromises.map((promise) => {
   return promise;
})


const runAllRequests = async () => {

await Promise.allSettled(eachPromises).then((res) => {

console.log('Success all requests!');
console.log(res); //this code is not executed if I use retries as shown above

}).catch((error) => {

 console.log("Promise Rejected");
 console.log('err: '+ error);

});

}

runAllRequests();  

},
....


But if I do not use retries then Promise.allSettled response works!

here the code without retries working:

      getProfile: function (retries = 3, backoff = 300) {

        var self = this;
        var app = self.$app;
        var $ = self.$$;

        console.log('user profile...');
        urlPath = "api_url_01";

        const retryCodes = [408, 500, 502, 503, 504, 522, 524, 400];

        return new Promise(function (resolve, reject) {

            app.request.promise({
              headers: {
                'Content-Type': 'application/json',
              },
              url: urlPath1,
              dataType: 'json',
              async: true,
              method: 'GET',
              data: {},
              cache: false,
              crossDomain: true,
            }).then(function (res) {

              /* handle the successful result */
              resolve(res);

            }).catch(function (err) {

              /* handle the error */ 
              console.log(err);

              reject(new Error("could't get user profile!"));

            });

          }).finally(function () {

            /* hide the preloader */
            console.log("handle finally...");

          });

      },


The init method again to init all requests… the line code responde now works!

initRequests: function (e) {

const thisPromises = [self.getProfile(), self.getPreferences(), self.getStores()];

var eachPromises = thisPromises.map((promise) => {
   return promise;
})


const runAllRequests = async () => {

await Promise.allSettled(eachPromises).then((res) => {

console.log('Success all requests!');
console.log(res); //this line code now works! and tells me which one was rejected or fulfilled

}).catch((error) => {

 console.log("Promise Rejected");
 console.log('err: '+ error);

});

}

runAllRequests();  

},
....


Anyone has any idea how to fix this or how to make it work with retries using app.request.promise calls?

thanks for the tips!

I think I found the solution!!!

I replaced this line!

return self.getProfile(retries - 1, backoff * 2) 

for this

resolve(self.getProfile(retries - 1, backoff * 2)); 
getProfile: function (retries = 3, backoff = 300) {

var self = this;
var app = self.$app;
var $ = self.$$;

console.log('user profile...');
var urlPath1 = "api_url_01";
const retryCodes = [408, 500, 502, 503, 504, 522, 524, 400];

return new Promise(function (resolve, reject) {

    app.request.promise({
      headers: {
        'Content-Type': 'application/json',
      },
      url: urlPath1,
      dataType: 'json',
      async: false,
      method: 'GET',
      data: {},
      cache: false,
      crossDomain: true,
    }).then(function (res) {

      console.log('success user');
      resolve(res);

    }).catch(function (err) {

      console.log('error user');
      console.log(err);
      const { status } = err;
      console.log({statusCode: status});

      if (retries > 0 && retryCodes.includes(status)) {

        setTimeout(() => {
          console.log('retry');
         resolve(self.getProfile(retries - 1, backoff * 2)); 
 //I changed this line to resolve(self.getProfile(retries - 1, backoff * 2)); 
        }, 500);

        } else {

        reject(new Error("could't get user profile!"));

        }

    });

});

now it works and retry 3 time before replying! initRequests stay the same as before!

initRequests: function (e) {

const thisPromises = [self.getProfile(), self.getPreferences(), self.getStores()];

var eachPromises = thisPromises.map((promise) => {
   return promise;
})


const runAllRequests = async () => {

await Promise.allSettled(eachPromises).then((res) => {

console.log('Success all requests!');
console.log(res); //this line code now works even with retries! 

}).catch((error) => {

 console.log("Promise Rejected");
 console.log('err: '+ error);

});

}

runAllRequests();  

},
....

now I get fulfilled and rejected after all retries have finished for each promise being called!

I hope this help others that want to use retries with app.request promises and make use of promises.allSettled for making an array a-synchronic api calls waiting the final reply of all at the end! :+1:

1 Like

Hi @rapgithub, I just wanted to thank you for this piece of code!

One small note, you declare the backoff but never actually use it in your setTimeout() function.

1 Like

welcome! :slight_smile:
we are here to support each other!! nice to hear it was useful!!

it is used here… backoff * 2 again

resolve(self.getProfile(retries - 1, backoff * 2)); 

If you want some updates I made to the code above here the code using store.js
with last version of f7:

    getStores({
      state
    }, {
      $f7, $,
      retries,
      backoff
    }, ) {

      var data = {
        "bucket_identifiers": [
          ...
        ],
      };

      const retryCodes = [408, 500, 502, 503, 504, 522, 524];

      state.storesLoading = true;

      return new Promise(function (resolve, reject) {

        request({
            headers: {
              'Content-Type': 'application/json',
            },
            url: `https://url_path/v1`,
            dataType: 'json',
            async: true,
            method: 'POST',
            data: JSON.stringify(data),
            cache: false,
            crossDomain: true,
          })
          .then((res) => {

            setTimeout(() => {
              state.storesLoading = false;
              state.stores = res.data.stores;
              resolve(res.data);
              //if array not empty
              if (res.data.stores.length > 0) {
                do something...
              }
            }, 1000);

          }).catch(function (err) {

            const {
              status
            } = err;

            if (retries > 0 && retryCodes.includes(status)) {

              setTimeout(() => {

                console.log("retrying: getting stores... retries left... " + retries);
                resolve(store.dispatch('getStores', {
                  $f7, $,
                  retries: retries - 1,
                  backoff: backoff * 2
                }));

              }, 500);

            } else {

              setTimeout(() => {

                state.storesLoading = false;
                state.stores = [];
                reject(err);

              }, 500);

            }

          })



      });

    },