ember.jspromiseember.js-2

Promise Retry Wrapper for Ember


I have a snippet of Ember code that calls an API end point and populates an array when a response arrives (there are other items added to the array independently of the API call. I omitted irrelevant code for simplicity):

descriptor: Ember.computed("qParams", function(){
    let qParams = this.get("qParams");
    let data = new Ember.A();
    let callHomePromise = this.get("store").find('info-extractor', qParams)
    .then(item => { data.pushObject(item); });
    return data;
    })

This code works fine and does what it is intended to do. I would like to create a retrier: in case this.get("store").find fails due to the underlying AJAX call responding with 401, for example, I would give it a couple more tries. Based on this answer

https://stackoverflow.com/a/51332115/1518685

I devised the following wrapper:

export default function (promiseFactory) {

  let retryChain = Ember.RSVP.reject();
  for (var count = 0; count < 3; count++) {
  retryChain = retryChain.catch(reason => {
      return new Ember.RSVP.Promise((resolver, rejector) => {
        promiseFactory().catch(r => {
        setTimeout(rejector.bind(null, reason), 1000);
      }).then(ok => { resolver(ok); })
      });
    });
  }

  return retryChain;
}

Which I execute the following way:

import retrier from 'project/utils/retrier';

//....

descriptor: Ember.computed("qParams", function(){
    let qParams = this.get("qParams");
    let data = new Ember.A();
    let callHomePromise = retrier(() => { 
         return this.get("store").find('info-extractor', qParams); 
        }).then(item => { data.pushObject(item); })
          .catch(reason => { /* do stuff with reason */});
    return data;
    })

I simulated bad requests (by setting faulty qParams variable) and observing multiple AJAX requests failing and eventually permanent failure gets captured within the catch() method after the retrier.

However, when the call is successful, the retrier promise never resolves and I can't figure our why?

Any help would be highly appreciated.


Solution

  • This part of the code

        return new Ember.RSVP.Promise((resolver, rejector) => {
          promiseFactory().catch(r => {
          setTimeout(rejector.bind(null, reason), 1000);
        })
    

    never calls resolver so it can't possibly succeed and reach the following then. Move the following then into the expression like this:

      retryChain = retryChain.catch(reason => {
        return new Ember.RSVP.Promise((resolver, rejector) => {
          promiseFactory().then(ok => { resolver(ok); }, r => {
            setTimeout(rejector.bind(null, reason), 1000);
          });
        });
      });