Add support for canceling in-flight requests

Repeat requests, if they already exist in the
in-flight request map, will cause the previous
request to cancel.

The implementation of the unique key is the
responsibility of individual datasources.
This commit is contained in:
stuart nelson 2016-06-08 18:04:31 +02:00
parent ffac5c1299
commit 6da7ed9706

View File

@ -7,7 +7,7 @@ define([
function (angular, _, coreModule, config) {
'use strict';
coreModule.default.service('backendSrv', function($http, alertSrv, $timeout) {
coreModule.default.service('backendSrv', function($http, alertSrv, $timeout, $q) {
var self = this;
this.get = function(url, params) {
@ -91,8 +91,25 @@ function (angular, _, coreModule, config) {
});
};
var datasourceInFlightRequests = {};
var HTTP_REQUEST_ABORTED = -1;
this.datasourceRequest = function(options) {
options.retry = options.retry || 0;
// A cacheKey is provided by the datasource as a unique identifier for a
// particular query. If the cacheKey exists, the promise it is keyed to
// is canceled, canceling the previous datasource request if it is still
// in-flight.
var canceler;
if (options.cacheKey) {
if (canceler = datasourceInFlightRequests[options.cacheKey]) {
canceler.resolve();
}
canceler = $q.defer();
options.timeout = canceler.promise;
datasourceInFlightRequests[options.cacheKey] = canceler;
}
var requestIsLocal = options.url.indexOf('/') === 0;
var firstAttempt = options.retry === 0;
@ -102,10 +119,25 @@ function (angular, _, coreModule, config) {
}
return $http(options).then(null, function(err) {
if (err.status === HTTP_REQUEST_ABORTED) {
// Need to return the right data structure so it has no effect on
// iterating over returned data in datasource.ts#115
// TODO: Hitting another refresh cancels the "loading" animation on
// panes. Figure out how to keep it going.
return {
data: {
data: {
result: []
}
}
};
}
// handle unauthorized for backend requests
if (requestIsLocal && firstAttempt && err.status === 401) {
return self.loginPing().then(function() {
options.retry = 1;
canceler.resolve();
return self.datasourceRequest(options);
});
}