You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by ma...@apache.org on 2017/10/04 17:23:19 UTC

[incubator-superset] branch master updated: [Bugfix/Feature] Fixed slice render staggering on dashboard first load (#3478)

This is an automated email from the ASF dual-hosted git repository.

maximebeauchemin pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-superset.git


The following commit(s) were added to refs/heads/master by this push:
     new e95132d  [Bugfix/Feature] Fixed slice render staggering on dashboard first load (#3478)
e95132d is described below

commit e95132ddc3521adf23e5721a7e1bdb93df53c351
Author: Jeff Niu <je...@gmail.com>
AuthorDate: Wed Oct 4 10:23:17 2017 -0700

    [Bugfix/Feature] Fixed slice render staggering on dashboard first load (#3478)
    
    * Feature: disable dashboard refresh staggering
    
    * Removed refresh staggering everywhere except during periodic render
---
 docs/faq.rst                                       | 25 +++++++++--
 .../assets/javascripts/dashboard/Dashboard.jsx     | 48 +++++++++++-----------
 .../javascripts/dashboard/components/Controls.jsx  |  5 +--
 superset/assets/javascripts/modules/superset.js    |  4 ++
 4 files changed, 51 insertions(+), 31 deletions(-)

diff --git a/docs/faq.rst b/docs/faq.rst
index 1c70fc8..cee767a 100644
--- a/docs/faq.rst
+++ b/docs/faq.rst
@@ -128,8 +128,11 @@ be applied, it's as simple as that.
 
 How to limit the timed refresh on a dashboard?
 ----------------------------------------------
-By default, the dashboard timed refresh feature allows you to automatically requery every slice on a dashboard according to a set schedule. Sometimes, however, you won't want all of the slices to be refreshed - especially if some data is slow moving, or run heavy queries.
-To exclude specific slices from the timed refresh process, add the ``timed_refresh_immune_slices`` key to the dashboard ``JSON Metadata`` field:
+By default, the dashboard timed refresh feature allows you to automatically re-query every slice
+on a dashboard according to a set schedule. Sometimes, however, you won't want all of the slices
+to be refreshed - especially if some data is slow moving, or run heavy queries. To exclude specific
+slices from the timed refresh process, add the ``timed_refresh_immune_slices`` key to the dashboard
+``JSON Metadata`` field:
 
 ..code::
 
@@ -140,8 +143,22 @@ To exclude specific slices from the timed refresh process, add the ``timed_refre
         "timed_refresh_immune_slices": [324]
     }
 
-In the example above, if a timed refresh is set for the dashboard, then every slice except 324 will be automatically requeried on schedule.
+In the example above, if a timed refresh is set for the dashboard, then every slice except 324 will
+be automatically re-queried on schedule.
 
+Slice refresh will also be staggered over the specified period. You can turn off this staggering
+by setting the ``stagger_refresh`` to ``false`` and modify the stagger period by setting
+``stagger_time`` to a value in milliseconds in the ``JSON Metadata`` field:
+
+..code::
+
+    {
+        "stagger_refresh": false,
+        "stagger_time": 2500
+    }
+
+Here, the entire dashboard will refresh at once if periodic refresh is on. The stagger time of
+2.5 seconds is ignored.
 
 Why does fabmanager or superset freezed/hung/not responding when started (my home directory is NFS mounted)?
 -----------------------------------------------------------------------------------------
@@ -188,7 +205,7 @@ Please note that pretty much any databases that have a SqlAlchemy integration sh
 How can i configure OAuth authentication and authorization?
 -----------------------------------------------------------
 
-You can take a look at this Flask-AppBuilder `configuration example 
+You can take a look at this Flask-AppBuilder `configuration example
 <https://github.com/dpgaspar/Flask-AppBuilder/blob/master/examples/oauth/config.py>`_.
 
 How can I set a default filter on my dashboard?
diff --git a/superset/assets/javascripts/dashboard/Dashboard.jsx b/superset/assets/javascripts/dashboard/Dashboard.jsx
index eb471da..5d150a2 100644
--- a/superset/assets/javascripts/dashboard/Dashboard.jsx
+++ b/superset/assets/javascripts/dashboard/Dashboard.jsx
@@ -126,7 +126,8 @@ export function dashboardContainer(dashboard, datasources, userid) {
         }
       });
       this.loadPreSelectFilters();
-      this.startPeriodicRender(0);
+      this.renderSlices(this.sliceObjects);
+      this.firstLoad = false;
       this.bindResizeToWindowResize();
     },
     onChange() {
@@ -254,25 +255,31 @@ export function dashboardContainer(dashboard, datasources, userid) {
         this.refreshTimer = null;
       }
     },
+    renderSlices(slices, force = false, interval = 0) {
+      if (!interval) {
+        slices.forEach(slice => slice.render(force));
+        return;
+      }
+      const meta = this.metadata;
+      const refreshTime = Math.max(interval, meta.stagger_time || 5000); // default 5 seconds
+      if (typeof meta.stagger_refresh !== 'boolean') {
+        meta.stagger_refresh = meta.stagger_refresh === undefined ?
+          true : meta.stagger_refresh === 'true';
+      }
+      const delay = meta.stagger_refresh ? refreshTime / (slices.length - 1) : 0;
+      slices.forEach((slice, i) => {
+        setTimeout(() => slice.render(force), delay * i);
+      });
+    },
     startPeriodicRender(interval) {
       this.stopPeriodicRender();
       const dash = this;
       const immune = this.metadata.timed_refresh_immune_slices || [];
-      const maxRandomDelay = Math.max(interval * 0.2, 5000);
       const refreshAll = () => {
-        dash.sliceObjects.forEach((slice) => {
-          const force = !dash.firstLoad;
-          if (immune.indexOf(slice.data.slice_id) === -1) {
-            setTimeout(() => {
-              slice.render(force);
-            },
-            // Randomize to prevent all widgets refreshing at the same time
-            maxRandomDelay * Math.random());
-          }
-        });
-        dash.firstLoad = false;
+        const slices = dash.sliceObjects
+          .filter(slice => immune.indexOf(slice.data.slice_id) === -1);
+        dash.renderSlices(slices, true, interval * 0.2);
       };
-
       const fetchAndRender = function () {
         refreshAll();
         if (interval > 0) {
@@ -285,16 +292,9 @@ export function dashboardContainer(dashboard, datasources, userid) {
     },
     refreshExcept(sliceId) {
       const immune = this.metadata.filter_immune_slices || [];
-      this.sliceObjects.forEach((slice) => {
-        if (slice.data.slice_id !== sliceId && immune.indexOf(slice.data.slice_id) === -1) {
-          slice.render();
-          const sliceSeletor = $(`#${slice.data.slice_id}-cell`);
-          sliceSeletor.addClass('slice-cell-highlight');
-          setTimeout(function () {
-            sliceSeletor.removeClass('slice-cell-highlight');
-          }, 1200);
-        }
-      });
+      const slices = this.sliceObjects.filter(slice =>
+        slice.data.slice_id !== sliceId && immune.indexOf(slice.data.slice_id) === -1);
+      this.renderSlices(slices);
     },
     clearFilters(sliceId) {
       delete this.filters[sliceId];
diff --git a/superset/assets/javascripts/dashboard/components/Controls.jsx b/superset/assets/javascripts/dashboard/components/Controls.jsx
index e18c270..5d24055 100644
--- a/superset/assets/javascripts/dashboard/components/Controls.jsx
+++ b/superset/assets/javascripts/dashboard/components/Controls.jsx
@@ -35,9 +35,8 @@ class Controls extends React.PureComponent {
     });
   }
   refresh() {
-    this.props.dashboard.sliceObjects.forEach((slice) => {
-      slice.render(true);
-    });
+    // Force refresh all slices
+    this.props.dashboard.renderSlices(this.props.dashboard.sliceObjects, true);
   }
   changeCss(css) {
     this.setState({ css });
diff --git a/superset/assets/javascripts/modules/superset.js b/superset/assets/javascripts/modules/superset.js
index a1723eb..6570aba 100644
--- a/superset/assets/javascripts/modules/superset.js
+++ b/superset/assets/javascripts/modules/superset.js
@@ -65,6 +65,7 @@ const px = function (state) {
     const container = $(selector);
     const sliceId = data.slice_id;
     const formData = applyDefaultFormData(data.form_data);
+    const sliceCell = $(`#${data.slice_id}-cell`);
     slice = {
       data,
       formData,
@@ -114,6 +115,7 @@ const px = function (state) {
 
         token.find('img.loading').hide();
         container.fadeTo(0.5, 1);
+        sliceCell.removeClass('slice-cell-highlight');
         container.show();
 
         $('.query-and-save button').removeAttr('disabled');
@@ -139,6 +141,7 @@ const px = function (state) {
         let errorMsg = msg;
         token.find('img.loading').hide();
         container.fadeTo(0.5, 1);
+        sliceCell.removeClass('slice-cell-highlight');
         let errHtml = '';
         let o;
         try {
@@ -211,6 +214,7 @@ const px = function (state) {
         controls.find('a.exportCSV').attr('href', getExploreUrl(formDataExtra, 'csv'));
         token.find('img.loading').show();
         container.fadeTo(0.5, 0.25);
+        sliceCell.addClass('slice-cell-highlight');
         container.css('height', this.height());
         $.ajax({
           url: this.jsonEndpoint(formDataExtra),

-- 
To stop receiving notification emails like this one, please contact
['"commits@superset.apache.org" <co...@superset.apache.org>'].