Explorar o código

AMBARI-7483 Slider View: Stopping ResourceManager results in multiple calls waiting to finish. (atkach)

atkach %!s(int64=10) %!d(string=hai) anos
pai
achega
1d7fa6ad02

+ 14 - 1
contrib/views/slider/src/main/resources/ui/app/controllers/slider_apps_controller.js

@@ -17,5 +17,18 @@
  */
 
 App.SliderAppsController = Ember.ArrayController.extend({
-
+  /**
+   * show modal popup that says apps currently unavailable
+   */
+  showUnavailableAppsPopup: function() {
+    Bootstrap.ModalManager.open(
+      "apps-warning-modal",
+      Em.I18n.t('common.warning'),
+      'unavailable_apps',
+      [
+        Ember.Object.create({title: Em.I18n.t('ok'), dismiss: 'modal'})
+      ],
+      this
+    );
+  }
 });

+ 6 - 1
contrib/views/slider/src/main/resources/ui/app/helpers/ajax.js

@@ -85,6 +85,11 @@ var urls = {
       Accept: "text/plain; charset=utf-8",
       "Content-Type": "text/plain; charset=utf-8"
     },
+    'format': function() {
+      return {
+        timeout: 20000
+      };
+    },
     schema: {
       required: ['items'],
       properties: {
@@ -329,7 +334,7 @@ var ajax = Em.Object.extend({
     opt.error = function (request, ajaxOptions, error) {
       if (config.error) {
         config.sender[config.error](request, ajaxOptions, error, opt, params);
-      } else {
+      } else if (config.sender.defaultErrorHandler) {
         config.sender.defaultErrorHandler.call(config.sender, request, opt.url, opt.type, opt.showErrorPopup);
       }
     };

+ 1 - 1
contrib/views/slider/src/main/resources/ui/app/initialize.js

@@ -113,7 +113,7 @@ App.initializer({
     });
     application.SliderController.proto().initResources();
     application.ApplicationTypeMapper.load();
-    application.SliderAppsMapper.loop('load');
+    application.SliderAppsMapper.run('load');
   }
 });
 

+ 37 - 2
contrib/views/slider/src/main/resources/ui/app/mappers/slider_apps_mapper.js

@@ -30,17 +30,47 @@ App.SliderAppsMapper = App.Mapper.createWithMixins(App.RunPeriodically, {
     'THAWED': 'RUNNING'
   },
 
+  /**
+   * @type {bool}
+   */
+  isWarningPopupShown: false,
+
+  /**
+   * @type {bool}
+   */
+  isChained: true,
   /**
    * Load data from <code>App.urlPrefix + this.urlSuffix</code> one time
    * @method load
    * @return {$.ajax}
    */
   load: function () {
-    return App.ajax.send({
+    var self = this;
+    var dfd = $.Deferred();
+
+    App.ajax.send({
       name: 'mapper.applicationApps',
       sender: this,
       success: 'parse'
-    });
+    }).fail(function(jqXHR, textStatus){
+        if (textStatus === "timeout" && !self.get('isWarningPopupShown')) {
+          self.set('isWarningPopupShown', true);
+          window.App.__container__.lookup('controller:SliderApps').showUnavailableAppsPopup();
+        }
+      }).complete(function(){
+        dfd.resolve();
+      })
+    return dfd.promise();
+  },
+
+  /**
+   * close warning popup if apps became available
+   * @return {*}
+   */
+  closeWarningPopup: function() {
+    if (Bootstrap.ModalManager.get('apps-warning-modal')) {
+      Bootstrap.ModalManager.close('apps-warning-modal');
+    }
   },
 
   /**
@@ -199,6 +229,11 @@ App.SliderAppsMapper = App.Mapper.createWithMixins(App.RunPeriodically, {
       self = this,
       appsToDelete = App.SliderApp.store.all('sliderApp').get('content').mapProperty('id');
 
+    if (this.get('isWarningPopupShown')) {
+      this.closeWarningPopup();
+      this.set('isWarningPopupShown', false);
+    }
+
     data.items.forEach(function (app) {
       var componentsId = app.components ? self.parseComponents(app) : [],
         configs = app.configs ? self.parseConfigs(app) : {},

+ 34 - 3
contrib/views/slider/src/main/resources/ui/app/mixins/run_periodically.js

@@ -43,13 +43,19 @@ App.RunPeriodically = Ember.Mixin.create({
    */
   timer: null,
 
+  /**
+   * flag to indicate whether each call should be chained to previous one
+   * @type {bool}
+   */
+  isChained: false,
+
   /**
    * Run <code>methodName</code> periodically with <code>interval</code>
    * @param {string} methodName method name to run periodically
    * @param {bool} initRun should methodName be run before setInterval call (default - true)
    * @method run
    */
-  loop: function(methodName, initRun) {
+  run: function(methodName, initRun) {
     initRun = Em.isNone(initRun) ? true : initRun;
     var self = this,
       interval = this.get('interval');
@@ -57,9 +63,34 @@ App.RunPeriodically = Ember.Mixin.create({
     if (initRun) {
       this[methodName]();
     }
+
+    if (this.get('isChained')) {
+      this.loop(self, methodName, interval);
+    } else {
+      this.set('timer',
+        setInterval(function () {
+          self[methodName]();
+        }, interval)
+      );
+    }
+  },
+
+  /**
+   * Start chain of calls of <code>methodName</code> with <code>interval</code>
+   * next call made only after previous is finished
+   * callback should return deffered object to run next loop
+   * @param {object} context
+   * @param {string} methodName method name to run periodically
+   * @param {number} interval
+   * @method loop
+   */
+  loop: function (context, methodName, interval) {
+    var self = this;
     this.set('timer',
-      setInterval(function () {
-        self[methodName]();
+      setTimeout(function () {
+        context[methodName]().done(function () {
+          self.loop(context, methodName, interval);
+        });
       }, interval)
     );
   },

+ 19 - 0
contrib/views/slider/src/main/resources/ui/app/templates/unavailable_apps.hbs

@@ -0,0 +1,19 @@
+{{!
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements.  See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership.  The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License.  You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+}}
+
+{{t slider.apps.unavailable}}

+ 2 - 1
contrib/views/slider/src/main/resources/ui/app/translations.js

@@ -48,7 +48,7 @@ Em.I18n.translations = {
     'finished': 'Finished',
     'diagnostics': 'Diagnostics',
     'description': 'Description',
-    'status': 'Status',
+    'warning': 'Warning',
     'key': 'Key',
     'remove': 'Remove',
     'send': 'Send',
@@ -78,6 +78,7 @@ Em.I18n.translations = {
 
   'slider.apps.title': 'Slider Apps',
   'slider.apps.create': 'Create App',
+  'slider.apps.unavailable': 'HDFS or YARN services are currently unaccessible',
   'sliderApps.filters.info': '{0} of {1} sliders showing',
 
   'sliderApp.flex.invalid_counts': 'Instance counts should be integer and >= 0',