diff --git a/superset/assets/javascripts/SqlLab/components/VisualizeModal.jsx b/superset/assets/javascripts/SqlLab/components/VisualizeModal.jsx index 56a66d3a66ea0..ff9119a84ecf4 100644 --- a/superset/assets/javascripts/SqlLab/components/VisualizeModal.jsx +++ b/superset/assets/javascripts/SqlLab/components/VisualizeModal.jsx @@ -12,7 +12,6 @@ import shortid from 'shortid'; import { getExploreUrl } from '../../explore/exploreUtils'; import * as actions from '../actions'; import { VISUALIZE_VALIDATION_ERRORS } from '../constants'; -import { QUERY_TIMEOUT_THRESHOLD } from '../../constants'; import visTypes from '../../explore/stores/visTypes'; const CHART_TYPES = Object.keys(visTypes) @@ -33,6 +32,7 @@ const propTypes = { show: PropTypes.bool, datasource: PropTypes.string, errorMessage: PropTypes.string, + timeout: PropTypes.number, }; const defaultProps = { show: false, @@ -133,12 +133,13 @@ class VisualizeModal extends React.PureComponent { } buildVisualizeAdvise() { let advise; + const timeout = this.props.timeout; const queryDuration = moment.duration(this.props.query.endDttm - this.props.query.startDttm); - if (Math.round(queryDuration.asMilliseconds()) > QUERY_TIMEOUT_THRESHOLD) { + if (Math.round(queryDuration.asMilliseconds()) > timeout * 1000) { advise = ( This query took {Math.round(queryDuration.asSeconds())} seconds to run, - and the explore view times out at {QUERY_TIMEOUT_THRESHOLD / 1000} seconds, + and the explore view times out at {timeout} seconds, following this flow will most likely lead to your query timing out. We recommend your summarize your data further before following that flow. If activated you can use the CREATE TABLE AS feature @@ -291,6 +292,7 @@ function mapStateToProps(state) { return { datasource: state.datasource, errorMessage: state.errorMessage, + timeout: state.common ? state.common.SUPERSET_WEBSERVER_TIMEOUT : null, }; } diff --git a/superset/assets/javascripts/constants.js b/superset/assets/javascripts/constants.js deleted file mode 100644 index cbb74800a00c5..0000000000000 --- a/superset/assets/javascripts/constants.js +++ /dev/null @@ -1 +0,0 @@ -export const QUERY_TIMEOUT_THRESHOLD = 45000; diff --git a/superset/assets/javascripts/dashboard/Dashboard.jsx b/superset/assets/javascripts/dashboard/Dashboard.jsx index 3c7b912d65dac..39eab0eec4259 100644 --- a/superset/assets/javascripts/dashboard/Dashboard.jsx +++ b/superset/assets/javascripts/dashboard/Dashboard.jsx @@ -11,10 +11,12 @@ import AlertsWrapper from '../components/AlertsWrapper'; import '../../stylesheets/dashboard.css'; -const px = require('../modules/superset'); +const superset = require('../modules/superset'); const urlLib = require('url'); const utils = require('../modules/utils'); +let px; + appSetup(); export function getInitialState(boostrapData) { @@ -368,6 +370,7 @@ $(document).ready(() => { const dashboardData = $('.dashboard').data('bootstrap'); const state = getInitialState(dashboardData); + px = superset(state); const dashboard = dashboardContainer(state.dashboard, state.datasources, state.user_id); initDashboardView(dashboard); dashboard.init(); diff --git a/superset/assets/javascripts/explore/actions/chartActions.js b/superset/assets/javascripts/explore/actions/chartActions.js index a9e5d1d379835..beca6ef8a2468 100644 --- a/superset/assets/javascripts/explore/actions/chartActions.js +++ b/superset/assets/javascripts/explore/actions/chartActions.js @@ -1,6 +1,5 @@ import { getExploreUrl } from '../exploreUtils'; import { getFormDataFromControls } from '../stores/store'; -import { QUERY_TIMEOUT_THRESHOLD } from '../../constants'; import { triggerQuery } from './exploreActions'; const $ = window.$ = require('jquery'); @@ -24,8 +23,8 @@ export function chartUpdateStopped(queryRequest) { } export const CHART_UPDATE_TIMEOUT = 'CHART_UPDATE_TIMEOUT'; -export function chartUpdateTimeout(statusText) { - return { type: CHART_UPDATE_TIMEOUT, statusText }; +export function chartUpdateTimeout(statusText, timeout) { + return { type: CHART_UPDATE_TIMEOUT, statusText, timeout }; } export const CHART_UPDATE_FAILED = 'CHART_UPDATE_FAILED'; @@ -49,7 +48,7 @@ export function removeChartAlert() { } export const RUN_QUERY = 'RUN_QUERY'; -export function runQuery(formData, force = false) { +export function runQuery(formData, force = false, timeout = 60) { return function (dispatch, getState) { const { explore } = getState(); const lastQueryFormData = getFormDataFromControls(explore.controls); @@ -62,12 +61,12 @@ export function runQuery(formData, force = false) { }, error(err) { if (err.statusText === 'timeout') { - dispatch(chartUpdateTimeout(err.statusText)); + dispatch(chartUpdateTimeout(err.statusText, timeout)); } else if (err.statusText !== 'abort') { dispatch(chartUpdateFailed(err.responseJSON)); } }, - timeout: QUERY_TIMEOUT_THRESHOLD, + timeout: timeout * 1000, }); dispatch(chartUpdateStarted(queryRequest, lastQueryFormData)); dispatch(triggerQuery(false)); diff --git a/superset/assets/javascripts/explore/components/ChartContainer.jsx b/superset/assets/javascripts/explore/components/ChartContainer.jsx index d5b4545192307..e8766d939cdbf 100644 --- a/superset/assets/javascripts/explore/components/ChartContainer.jsx +++ b/superset/assets/javascripts/explore/components/ChartContainer.jsx @@ -44,6 +44,7 @@ const propTypes = { standalone: PropTypes.bool, datasourceType: PropTypes.string, datasourceId: PropTypes.number, + timeout: PropTypes.number, }; class ChartContainer extends React.PureComponent { @@ -148,7 +149,7 @@ class ChartContainer extends React.PureComponent { } runQuery() { - this.props.actions.runQuery(this.props.formData, true); + this.props.actions.runQuery(this.props.formData, true, this.props.timeout); } updateChartTitle(newTitle) { @@ -346,6 +347,7 @@ function mapStateToProps({ explore, chart }) { chartUpdateStartTime: chart.chartUpdateStartTime, latestQueryFormData: chart.latestQueryFormData, queryResponse: chart.queryResponse, + timeout: explore.common.conf.SUPERSET_WEBSERVER_TIMEOUT, }; } diff --git a/superset/assets/javascripts/explore/reducers/chartReducer.js b/superset/assets/javascripts/explore/reducers/chartReducer.js index 9337b24a24f1c..44e95573335e2 100644 --- a/superset/assets/javascripts/explore/reducers/chartReducer.js +++ b/superset/assets/javascripts/explore/reducers/chartReducer.js @@ -1,7 +1,6 @@ /* eslint camelcase: 0 */ import { now } from '../../modules/dates'; import * as actions from '../actions/chartActions'; -import { QUERY_TIMEOUT_THRESHOLD } from '../../constants'; export default function chartReducer(state = {}, action) { const actionHandlers = { @@ -41,11 +40,13 @@ export default function chartReducer(state = {}, action) { [actions.CHART_UPDATE_TIMEOUT]() { return Object.assign({}, state, { chartStatus: 'failed', - chartAlert: 'Query timeout - visualization query are set to timeout at ' + - `${QUERY_TIMEOUT_THRESHOLD / 1000} seconds. ` + - 'Perhaps your data has grown, your database is under unusual load, ' + - 'or you are simply querying a data source that is to large to be processed within the timeout range. ' + - 'If that is the case, we recommend that you summarize your data further.', + chartAlert: ( + 'Query timeout - visualization query are set to timeout at ' + + `${action.timeout} seconds. ` + + 'Perhaps your data has grown, your database is under unusual load, ' + + 'or you are simply querying a data source that is to large ' + + 'to be processed within the timeout range. ' + + 'If that is the case, we recommend that you summarize your data further.'), }); }, [actions.CHART_UPDATE_FAILED]() { diff --git a/superset/assets/javascripts/modules/superset.js b/superset/assets/javascripts/modules/superset.js index eccdda4a312f7..6b342f7d6c606 100644 --- a/superset/assets/javascripts/modules/superset.js +++ b/superset/assets/javascripts/modules/superset.js @@ -4,13 +4,13 @@ import Mustache from 'mustache'; import vizMap from '../../visualizations/main'; import { getExploreUrl } from '../explore/exploreUtils'; import { applyDefaultFormData } from '../explore/stores/store'; -import { QUERY_TIMEOUT_THRESHOLD } from '../constants'; const utils = require('./utils'); /* eslint wrap-iife: 0 */ -const px = function () { +const px = function (state) { let slice; + const timeout = state.common.conf.SUPERSET_WEBSERVER_TIMEOUT; function getParam(name) { /* eslint no-useless-escape: 0 */ const formattedName = name.replace(/[\[]/, '\\[').replace(/[\]]/, '\\]'); @@ -157,8 +157,10 @@ const px = function () { } if (xhr) { if (xhr.statusText === 'timeout') { - errHtml += '
' + - `Query timeout - visualization query are set to time out at ${QUERY_TIMEOUT_THRESHOLD / 1000} seconds.
`; + errHtml += ( + '
' + + 'Query timeout - visualization query are set to time out ' + + `at ${timeout} seconds.
`); } else { const extendedMsg = this.getErrorMsg(xhr); if (extendedMsg) { @@ -210,7 +212,7 @@ const px = function () { container.css('height', this.height()); $.ajax({ url: this.jsonEndpoint(), - timeout: QUERY_TIMEOUT_THRESHOLD, + timeout: timeout * 1000, success: (queryResponse) => { try { vizMap[formData.viz_type](this, queryResponse); @@ -251,5 +253,5 @@ const px = function () { initFavStars, Slice, }; -}(); +}; module.exports = px; diff --git a/superset/assets/spec/javascripts/sqllab/VisualizeModal_spec.jsx b/superset/assets/spec/javascripts/sqllab/VisualizeModal_spec.jsx index eab4608889f13..41c23bb9a0628 100644 --- a/superset/assets/spec/javascripts/sqllab/VisualizeModal_spec.jsx +++ b/superset/assets/spec/javascripts/sqllab/VisualizeModal_spec.jsx @@ -25,7 +25,10 @@ global.notify = { describe('VisualizeModal', () => { const middlewares = [thunk]; const mockStore = configureStore(middlewares); - const initialState = sqlLabReducer(undefined, {}); + const initialState = sqlLabReducer({}, {}); + initialState.common = { + SUPERSET_WEBSERVER_TIMEOUT: 45, + }; const store = mockStore(initialState); const mockedProps = { show: true,