1

I'm trying to use HTTP-Interceptor to handle when a $http request times out and to ensure that the requesting function actually gets the response it is after. Retry request with $http interceptor works for me BUT, it has an immediate retry. What I'm really more interested in doing is to wait 5 seconds, and then retry. Furthermore, I also want the user to be able to trigger an immediate retry.

What I'm attempting to do is something like the below:

joinApp.factory('httpResponseErrorInterceptor',function($q, $injector, $interval) {
  return {
    'responseError': function(response) {
      if (response.status === 0) {
        setTimeToRetry(5); //sets retry timeout to 5 seconds, and starts an interval to reduce the count every second
        // should retry
        $interval(function(response) {
          if(getTimeToRetry() <= 0) { //when retry timeout gets to 0, then retry - this also allows for a method that sets the retry timeout to 0 earlier so that a user can make an immediate retry
            var $http = $injector.get('$http');
            return $http(response.config);
          }
        },1000)

      }
      // give up
      return $q.reject(response);
    }
  };
});

joinApp.config(function($httpProvider) {
  $httpProvider.interceptors.push('httpResponseErrorInterceptor');
});

(As you can see, I've very liberally copied the base code from that linked answer)

But what I'm finding, is that then when the $http request is retried, then it completes the HTTP request successfully, but the code that was looking for the original promise response does not actually get what its after. I'm GUESSING that this is because the existence of the $interval actually moves the response outside of the thread that the request was made in, so the response doesn't go to the same requester, but that's a guess.

What I've also tried is to chain the $interval promise with the $http promise. Something like

var retryIntervalPromise = $interval(function(response) {
  if(getTimeToRetry() <= 0) { //when retry timeout gets to 0, then retry
    var $http = $injector.get('$http');
    return $http(response.config);
  }
},1000)
.then(function() {
  var $http = $injector.get('$http');
            return $http(response.config);
            });
return retryIntervalPromise

But I've been informed that the only thing that can be done with the $interval promise is to cancel it, and that didn't seem to work anyway.

Does anybody have an idea for how this can be done? Or whether the intent works and I've just done something horribly wrong? Thanks!

Community
  • 1
  • 1
Jty.tan
  • 808
  • 9
  • 25
  • Can you share us the code for submitting the request. My thinking is that since you do the retry, the original promise not longer valid so you will have to update your waited promise with the one from retry. – kwangsa May 18 '15 at 02:24
  • Why are you using `$interval` and not `$timeout` if all you need is a delay? – New Dev May 18 '15 at 04:43
  • I'm using `$interval` so that I can - through user interaction - set the retry time to 0, and therefore force an immediate retry. – Jty.tan May 20 '15 at 03:34

1 Answers1

2

You can return a "delay" promise from the responseError function, to which you chain the $http promise to try again. This is a simple example with a fixed timeout:

            responseError: function(response) {
                if (response.status === 0) {
                    var $http = $injector.get('$http');

                    var deferred = $q.defer();

                    $timeout(function() {
                        deferred.resolve(true);
                    }, 5000);

                    return deferred.promise.then(function() {
                        return $http(response.config);
                    });
                }
                return $q.reject(response);
            }

If you need a variable delay, you could store it in a variable within a factory or other service and have the rest of the user interface change it there. The next time the timeout fires, it will read the new value of the interval from the singleton and wait accordingly before firing the request again.

nicolov
  • 131
  • 1
  • 5
  • That's a nifty way to delay the resolution of the promise. Exactly what I was looking for. – Alex Sep 26 '16 at 18:26