The API my webapp is talking to sometimes overloads and is sending 500 Internal Server Error if it cannot handle request.
There are 100+ different requests my web application can send, so if I implement retry on each individually, it will cost me hours of typing.
I'm already using $httpProvider interceptor, here it is (simplified)
$httpProvider.interceptors.push(function ($q) {
return {
responseError: function (response) {
switch (response.status) {
case 401 :
window.location = "/";
alert('Session has expired. Redirecting to login page');
break;
case 500 :
// TODO: retry the request
break;
}
return $q.reject(response);
}
};
});
How could I resend a request after getting 500 response code from the server?
Angular provides reference to the config object which was used by $http service for doing the request in the response (response.config). That means if we can inject $http service in the interceptor we can easily resend the request. Simple injecting of $http service in the interceptor is not possible because of the circular dependency but luckily there is a workaround for that.
This is an example how the implementation of a such interceptor can be done.
$httpProvider.interceptors.push(function ($q, $injector) {
var incrementalTimeout = 1000;
function retryRequest (httpConfig) {
var $timeout = $injector.get('$timeout');
var thisTimeout = incrementalTimeout;
incrementalTimeout *= 2;
return $timeout(function() {
var $http = $injector.get('$http');
return $http(httpConfig);
}, thisTimeout);
};
return {
responseError: function (response) {
if (response.status === 500) {
if (incrementalTimeout < 5000) {
return retryRequest(response.config);
}
else {
alert('The remote server seems to be busy at the moment. Please try again in 5 minutes');
}
}
else {
incrementalTimeout = 1000;
}
return $q.reject(response);
}
};
});
Note: In this example implementation the interceptor will retry the request until you receive a response with status that is different than 500. Improvement to this can be adding some timeout before retrying and retrying only once.
You can check for any possible server side errors by expanding the status code check a little more. This interceptor will attempt to retry the request multiple times and will do so on any response code 500 or higher. It will wait 1 second before retrying, and give up after 3 tries.
$httpProvider.interceptors.push(function ($q, $injector) {
var retries = 0,
waitBetweenErrors = 1000,
maxRetries = 3;
function onResponseError(httpConfig) {
var $http = $injector.get('$http');
setTimeout(function () {
return $http(httpConfig);
}, waitBetweenErrors);
}
return {
responseError: function (response) {
if (response.status >= 500 && retries < maxRetries) {
retries++;
return onResponseError(response.config);
}
retries = 0;
return $q.reject(response);
}
};
});