From 6da7ed970611529f30dc72adf482d10f28b071d4 Mon Sep 17 00:00:00 2001 From: stuart nelson Date: Wed, 8 Jun 2016 18:04:31 +0200 Subject: [PATCH] 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. --- public/app/core/services/backend_srv.js | 34 ++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/public/app/core/services/backend_srv.js b/public/app/core/services/backend_srv.js index f27e427c70b..f1ab7b5824b 100644 --- a/public/app/core/services/backend_srv.js +++ b/public/app/core/services/backend_srv.js @@ -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); }); }