Repository: ambari Updated Branches: refs/heads/branch-2.5 d64fd8f1e -> 714e60115
AMBARI-19939 Service Config pages load very slowly Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/714e6011 Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/714e6011 Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/714e6011 Branch: refs/heads/branch-2.5 Commit: 714e60115db46584920e3cb1eae7c84ae31b9f5d Parents: d64fd8f Author: Denys Buzhor <[email protected]> Authored: Thu Feb 9 14:16:32 2017 +0200 Committer: Denys Buzhor <[email protected]> Committed: Thu Feb 9 19:07:00 2017 +0200 ---------------------------------------------------------------------- .../controllers/main/service/info/configs.js | 13 ++- .../app/mixins/common/configs/configs_loader.js | 2 +- .../app/mixins/common/track_request_mixin.js | 36 +++++++- ambari-web/app/routes/main.js | 15 +++- .../main/host/configs_service_test.js | 2 + .../main/service/info/config_test.js | 87 +++++++++++++++++++- 6 files changed, 144 insertions(+), 11 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/714e6011/ambari-web/app/controllers/main/service/info/configs.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/controllers/main/service/info/configs.js b/ambari-web/app/controllers/main/service/info/configs.js index 59dbe1d..265a216 100644 --- a/ambari-web/app/controllers/main/service/info/configs.js +++ b/ambari-web/app/controllers/main/service/info/configs.js @@ -235,6 +235,7 @@ App.MainServiceInfoConfigsController = Em.Controller.extend(App.AddSecurityConfi */ clearStep: function () { this.abortRequests(); + App.router.get('mainController').stopPolling(); App.set('componentToBeAdded', {}); App.set('componentToBeDeleted', {}); this.clearLoadInfo(); @@ -289,7 +290,7 @@ App.MainServiceInfoConfigsController = Em.Controller.extend(App.AddSecurityConfi acc.push(i); return Array.prototype.concat.apply(acc, App.StackService.find(i).get('dependentServiceNames').toArray()).without(serviceName).uniq(); }, [])); - this.trackRequest(this.loadConfigTheme(serviceName).always(function () { + this.trackRequestChain(this.loadConfigTheme(serviceName).always(function () { if (self.get('preSelectedConfigVersion')) { self.loadPreSelectedConfigVersion(); } else { @@ -300,6 +301,16 @@ App.MainServiceInfoConfigsController = Em.Controller.extend(App.AddSecurityConfi }, /** + * Turn on polling when all requests are finished + */ + trackRequestsDidChange: function() { + var allCompleted = this.get('requestsInProgress').everyProperty('completed', true); + if (this.get('requestsInProgress').length && allCompleted) { + App.router.get('mainController').startPolling(); + } + }.observes('[email protected]'), + + /** * Generate "finger-print" for current <code>stepConfigs[0]</code> * Used to determine, if user has some unsaved changes (comparing with <code>hash</code>) * @returns {string|null} http://git-wip-us.apache.org/repos/asf/ambari/blob/714e6011/ambari-web/app/mixins/common/configs/configs_loader.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/mixins/common/configs/configs_loader.js b/ambari-web/app/mixins/common/configs/configs_loader.js index c888a3e..458c38f 100644 --- a/ambari-web/app/mixins/common/configs/configs_loader.js +++ b/ambari-web/app/mixins/common/configs/configs_loader.js @@ -103,7 +103,7 @@ App.ConfigsLoader = Em.Mixin.create(App.GroupsMappingMixin, { this.set('versionLoaded', false); this.set('selectedVersion', this.get('currentDefaultVersion')); this.set('preSelectedConfigVersion', null); - this.trackRequest(App.ajax.send({ + this.trackRequestChain(App.ajax.send({ name: 'service.serviceConfigVersions.get.current', sender: this, data: { http://git-wip-us.apache.org/repos/asf/ambari/blob/714e6011/ambari-web/app/mixins/common/track_request_mixin.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/mixins/common/track_request_mixin.js b/ambari-web/app/mixins/common/track_request_mixin.js index 6fcc991..07eaf6e 100644 --- a/ambari-web/app/mixins/common/track_request_mixin.js +++ b/ambari-web/app/mixins/common/track_request_mixin.js @@ -28,7 +28,36 @@ App.TrackRequestMixin = Em.Mixin.create({ * @method trackRequest */ trackRequest: function (request) { - this.get('requestsInProgress').push(request); + var requestId = this.get('requestsInProgress').length; + var self = this; + this.get('requestsInProgress').pushObject({ + request: request, + id: requestId, + status: request.state(), + completed: ['resolved', 'rejected'].contains(request.state()) + }); + request.always(function() { + Em.setProperties(self.get('requestsInProgress').findProperty('id', requestId), { + completed: true, + status: request.state() + }); + }); + }, + + /** + * This method used to put promise to requests queue which is waiting for another request to be put in tracking queue + * after tracking request promise will be completed. Basically it used for places where trackRequest called after + * tracked promise gets resolved. + * + * @param {$.ajax} request + */ + trackRequestChain: function(request) { + var dfd = $.Deferred(); + request.always(function() { + dfd.resolve(); + }); + this.trackRequest(request); + this.trackRequest(dfd); }, /** @@ -37,8 +66,9 @@ App.TrackRequestMixin = Em.Mixin.create({ */ abortRequests: function () { this.get('requestsInProgress').forEach(function(r) { - if (r && r.readyState !== 4) { - r.abort(); + var request = r.request; + if (request && request.readyState !== undefined && request.readyState !== 4) { + request.abort(); } }); this.get('requestsInProgress').clear(); http://git-wip-us.apache.org/repos/asf/ambari/blob/714e6011/ambari-web/app/routes/main.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/routes/main.js b/ambari-web/app/routes/main.js index 7abe22b..5ead230 100644 --- a/ambari-web/app/routes/main.js +++ b/ambari-web/app/routes/main.js @@ -229,7 +229,7 @@ module.exports = Em.Route.extend(App.RouterRedirections, { controller.connectOutlet('mainHostSummary'); }); } else - controller.connectOutlet('mainHostSummary'); + controller.connectOutlet('mainHostSummary'); }); } else if(App.Service.find().mapProperty('serviceName').contains('HIVE')) { App.router.get('configurationController').getConfigsByTags(tags).always(function () { @@ -717,6 +717,7 @@ module.exports = Em.Route.extend(App.RouterRedirections, { //if service is not existed then route to default service if (item.get('isLoaded')) { if (router.get('mainServiceItemController.isConfigurable')) { + router.get('mainController').stopPolling(); router.get('mainServiceItemController').connectOutlet('mainServiceInfoConfigs', item); } else { @@ -729,13 +730,19 @@ module.exports = Em.Route.extend(App.RouterRedirections, { } }); }, - exitRoute: function (router, context, callback) { + exitRoute: function (router, nextRoute, callback) { var controller = router.get('mainServiceInfoConfigsController'); + var exitCallback = function() { + if (!/\/main\/services\/\w+\/configs$/.test(nextRoute)) { + router.get('mainController').startPolling(); + } + callback(); + }; // If another user is running some wizard, current user can't save configs if (controller.hasUnsavedChanges() && !router.get('wizardWatcherController.isWizardRunning')) { - controller.showSavePopup(callback); + controller.showSavePopup(exitCallback); } else { - callback(); + exitCallback(); } } }), http://git-wip-us.apache.org/repos/asf/ambari/blob/714e6011/ambari-web/test/controllers/main/host/configs_service_test.js ---------------------------------------------------------------------- diff --git a/ambari-web/test/controllers/main/host/configs_service_test.js b/ambari-web/test/controllers/main/host/configs_service_test.js index deb01ae..85f98b3 100644 --- a/ambari-web/test/controllers/main/host/configs_service_test.js +++ b/ambari-web/test/controllers/main/host/configs_service_test.js @@ -107,11 +107,13 @@ describe('App.MainHostServiceConfigsController', function () { sinon.stub(controller, 'loadConfigTheme', function() { return { always: Em.K }; }); + sinon.stub(controller, 'trackRequest'); }); afterEach(function() { controller.loadCurrentVersions.restore(); controller.loadConfigTheme.restore(); App.themesMapper.generateAdvancedTabs.restore(); + controller.trackRequest.restore(); }); it("should set host", function () { controller.set('content', { http://git-wip-us.apache.org/repos/asf/ambari/blob/714e6011/ambari-web/test/controllers/main/service/info/config_test.js ---------------------------------------------------------------------- diff --git a/ambari-web/test/controllers/main/service/info/config_test.js b/ambari-web/test/controllers/main/service/info/config_test.js index a06ff8a..7a70127 100644 --- a/ambari-web/test/controllers/main/service/info/config_test.js +++ b/ambari-web/test/controllers/main/service/info/config_test.js @@ -38,6 +38,8 @@ describe("App.MainServiceInfoConfigsController", function () { beforeEach(function () { sinon.stub(App.themesMapper, 'generateAdvancedTabs').returns(Em.K); + sinon.stub(App.router.get('mainController'), 'startPolling'); + sinon.stub(App.router.get('mainController'), 'stopPolling'); mainServiceInfoConfigsController = getController(); }); @@ -45,6 +47,8 @@ describe("App.MainServiceInfoConfigsController", function () { afterEach(function() { App.themesMapper.generateAdvancedTabs.restore(); + App.router.get('mainController').startPolling.restore(); + App.router.get('mainController').stopPolling.restore(); }); describe("#getHash", function () { @@ -256,12 +260,14 @@ describe("App.MainServiceInfoConfigsController", function () { sinon.stub(mainServiceInfoConfigsController, "getHash", function () { return "hash" }); + sinon.stub(mainServiceInfoConfigsController, 'trackRequest'); }); afterEach(function () { mainServiceInfoConfigsController.get.restore(); mainServiceInfoConfigsController.restartServicePopup.restore(); mainServiceInfoConfigsController.getHash.restore(); + mainServiceInfoConfigsController.trackRequest.restore(); }); tests.forEach(function (t) { @@ -819,9 +825,86 @@ describe("App.MainServiceInfoConfigsController", function () { mainServiceInfoConfigsController.get('requestsInProgress').clear(); }); it("should set requestsInProgress", function () { + var dfd = $.Deferred(); mainServiceInfoConfigsController.get('requestsInProgress').clear(); - mainServiceInfoConfigsController.trackRequest({'request': {}}); - expect(mainServiceInfoConfigsController.get('requestsInProgress')[0]).to.eql({'request': {}}); + mainServiceInfoConfigsController.trackRequest(dfd); + expect(mainServiceInfoConfigsController.get('requestsInProgress')[0]).to.eql( + { + request: dfd, + id: 0, + status: 'pending', + completed: false + } + ); + }); + it('should update request status when it become resolved', function() { + var request = $.Deferred(); + mainServiceInfoConfigsController.get('requestsInProgress').clear(); + mainServiceInfoConfigsController.trackRequest(request); + expect(mainServiceInfoConfigsController.get('requestsInProgress')[0]).to.eql({ + request: request, + id: 0, + status: 'pending', + completed: false + }); + request.resolve(); + expect(mainServiceInfoConfigsController.get('requestsInProgress')[0]).to.eql({ + request: request, + id: 0, + status: 'resolved', + completed: true + }); + }); + }); + + describe('#trackRequestChain', function() { + beforeEach(function() { + mainServiceInfoConfigsController.get('requestsInProgress').clear(); + }); + it('should set 2 requests in to requestsInProgress list', function() { + mainServiceInfoConfigsController.trackRequestChain($.Deferred()); + expect(mainServiceInfoConfigsController.get('requestsInProgress')).to.have.length(2); + }); + it('should update status for both requests when tracked requests become resolved', function() { + var request = $.Deferred(), + requests; + mainServiceInfoConfigsController.trackRequestChain(request); + requests = mainServiceInfoConfigsController.get('requestsInProgress'); + assert.deepEqual(requests.mapProperty('status'), ['pending', 'pending'], 'initial statuses'); + assert.deepEqual(requests.mapProperty('completed'), [false, false], 'initial completed'); + request.reject(); + assert.deepEqual(requests.mapProperty('status'), ['rejected', 'resolved'], 'update status when rejected'); + assert.deepEqual(requests.mapProperty('completed'), [true, true], 'initial complete are false'); + }); + }); + + describe('#abortRequests', function() { + beforeEach(function() { + mainServiceInfoConfigsController.get('requestsInProgress').clear(); + }); + it('should clear requests when abort called', function() { + mainServiceInfoConfigsController.trackRequest($.Deferred()); + mainServiceInfoConfigsController.abortRequests(); + expect(mainServiceInfoConfigsController.get('requestsInProgress')).to.have.length(0); + }); + it('should abort requests which are not finished', function() { + var pendingRequest = { + abort: sinon.spy(), + readyState: 0, + state: sinon.spy(), + always: sinon.spy() + }; + var finishedRequest = { + abort: sinon.spy(), + readyState: 4, + state: sinon.spy(), + always: sinon.spy() + }; + mainServiceInfoConfigsController.trackRequest(pendingRequest); + mainServiceInfoConfigsController.trackRequest(finishedRequest); + mainServiceInfoConfigsController.abortRequests(); + expect(pendingRequest.abort.calledOnce).to.be.true; + expect(finishedRequest.abort.calledOnce).to.be.false; }); });
