Commit 726ecc0b authored by Nick Stenning's avatar Nick Stenning

Only make one request for features data at once

This was a fun bug. If multiple feature checks are done in rapid
succession when the features cache is empty (such as, for example,
during the first digest cycle at application boot time) then the
features client would keep kicking off HTTP requests until the first one
returned.

This would clearly be a misfeature, but wouldn't actually have caused
any problems but for the fact that the spinner in
`h/directives/simple-search.coffee` does this to determine whether to
spin:

    scope.$watch (-> $http.pendingRequests.length), (pending) ->
      scope.loading = (pending > 0)

This means that kicking off dozens of requests at a time keeps
invalidating the digest cycle (because the value of
`$http.pendingRequests.length` keeps changing), so it never ends. The
result is the ever-horrible `infdig` (infinite digest cycle) error from
Angular: https://docs.angularjs.org/error/$rootScope/infdig.
parent e003383b
...@@ -25,15 +25,24 @@ var CACHE_TTL = 5 * 60 * 1000; // 5 minutes ...@@ -25,15 +25,24 @@ var CACHE_TTL = 5 * 60 * 1000; // 5 minutes
function features ($document, $http, $log) { function features ($document, $http, $log) {
var cache = null; var cache = null;
var pending = false;
var featuresURL = new URL('/app/features', $document.prop('baseURI')); var featuresURL = new URL('/app/features', $document.prop('baseURI'));
function fetch() { function fetch() {
// Short-circuit if a fetch is already in progress...
if (pending) {
return;
}
pending = true;
$http.get(featuresURL) $http.get(featuresURL)
.success(function(data) { .success(function(data) {
cache = [Date.now(), data]; cache = [Date.now(), data];
}) })
.error(function() { .error(function() {
$log.warn('features service: failed to load features data'); $log.warn('features service: failed to load features data');
})
.finally(function() {
pending = false;
}); });
} }
......
...@@ -57,6 +57,13 @@ describe('h:features', function () { ...@@ -57,6 +57,13 @@ describe('h:features', function () {
$httpBackend.flush(); $httpBackend.flush();
}); });
it('fetch should only send one request at a time', function () {
defaultHandler();
features.fetch();
features.fetch();
$httpBackend.flush();
});
it('flagEnabled should retrieve features data', function () { it('flagEnabled should retrieve features data', function () {
defaultHandler(); defaultHandler();
features.flagEnabled('foo'); features.flagEnabled('foo');
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment