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 2024/06/20 21:28:53 UTC
(superset) branch master updated: feat: add new SQLLAB_FORCE_RUN_ASYNC feature flag (#29231)
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/superset.git
The following commit(s) were added to refs/heads/master by this push:
new 5e060cef7c feat: add new SQLLAB_FORCE_RUN_ASYNC feature flag (#29231)
5e060cef7c is described below
commit 5e060cef7c0ec197a44b92490eb11c5a39282c92
Author: Maxime Beauchemin <ma...@gmail.com>
AuthorDate: Thu Jun 20 14:28:46 2024 -0700
feat: add new SQLLAB_FORCE_RUN_ASYNC feature flag (#29231)
Co-authored-by: Geido <60...@users.noreply.github.com>
---
.../superset-ui-core/src/utils/featureFlags.ts | 1 +
.../src/components/InfoTooltip/index.tsx | 15 ++--
.../databases/DatabaseModal/ExtraOptions.tsx | 23 +++++-
superset/config.py | 2 +
superset/sqllab/sqllab_execution_context.py | 4 +-
tests/unit_tests/sql_lab_execution_context.py | 96 ++++++++++++++++++++++
6 files changed, 131 insertions(+), 10 deletions(-)
diff --git a/superset-frontend/packages/superset-ui-core/src/utils/featureFlags.ts b/superset-frontend/packages/superset-ui-core/src/utils/featureFlags.ts
index b3af431d52..fcc38dc2ec 100644
--- a/superset-frontend/packages/superset-ui-core/src/utils/featureFlags.ts
+++ b/superset-frontend/packages/superset-ui-core/src/utils/featureFlags.ts
@@ -57,6 +57,7 @@ export enum FeatureFlag {
TaggingSystem = 'TAGGING_SYSTEM',
Thumbnails = 'THUMBNAILS',
UseAnalagousColors = 'USE_ANALAGOUS_COLORS',
+ ForceSqlLabRunAsync = 'SQLLAB_FORCE_RUN_ASYNC',
}
export type ScheduleQueriesProps = {
diff --git a/superset-frontend/src/components/InfoTooltip/index.tsx b/superset-frontend/src/components/InfoTooltip/index.tsx
index cf10d873dd..1f160e47ae 100644
--- a/superset-frontend/src/components/InfoTooltip/index.tsx
+++ b/superset-frontend/src/components/InfoTooltip/index.tsx
@@ -17,12 +17,12 @@
* under the License.
*/
-import { styled } from '@superset-ui/core';
+import { styled, useTheme } from '@superset-ui/core';
import { Tooltip } from 'src/components/Tooltip';
import Icons from 'src/components/Icons';
export interface InfoTooltipProps {
- className?: string;
+ iconStyle?: React.CSSProperties;
tooltip: string;
placement?:
| 'bottom'
@@ -46,9 +46,6 @@ export interface InfoTooltipProps {
const StyledTooltip = styled(Tooltip)`
cursor: pointer;
- path:first-of-type {
- fill: ${({ theme }) => theme.colors.grayscale.base};
- }
`;
const StyledTooltipTitle = styled.span`
@@ -68,12 +65,18 @@ const defaultColor = 'rgba(0,0,0,0.9)';
export default function InfoTooltip({
tooltip,
+ iconStyle = {},
placement = 'right',
trigger = 'hover',
overlayStyle = defaultOverlayStyle,
bgColor = defaultColor,
viewBox = '0 -1 24 24',
}: InfoTooltipProps) {
+ const theme = useTheme();
+ const alteredIconStyle = {
+ ...iconStyle,
+ color: iconStyle.color || theme.colors.grayscale.base,
+ };
return (
<StyledTooltip
title={<StyledTooltipTitle>{tooltip}</StyledTooltipTitle>}
@@ -82,7 +85,7 @@ export default function InfoTooltip({
overlayStyle={overlayStyle}
color={bgColor}
>
- <Icons.InfoSolidSmall className="info-solid-small" viewBox={viewBox} />
+ <Icons.InfoSolidSmall style={alteredIconStyle} viewBox={viewBox} />
</StyledTooltip>
);
}
diff --git a/superset-frontend/src/features/databases/DatabaseModal/ExtraOptions.tsx b/superset-frontend/src/features/databases/DatabaseModal/ExtraOptions.tsx
index 9f48c2792c..6cf1deaac0 100644
--- a/superset-frontend/src/features/databases/DatabaseModal/ExtraOptions.tsx
+++ b/superset-frontend/src/features/databases/DatabaseModal/ExtraOptions.tsx
@@ -20,8 +20,11 @@ import { ChangeEvent, EventHandler } from 'react';
import cx from 'classnames';
import {
t,
- SupersetTheme,
DatabaseConnectionExtension,
+ isFeatureEnabled,
+ SupersetTheme,
+ useTheme,
+ FeatureFlag,
} from '@superset-ui/core';
import InfoTooltip from 'src/components/InfoTooltip';
import IndeterminateCheckbox from 'src/components/IndeterminateCheckbox';
@@ -68,10 +71,16 @@ const ExtraOptions = ({
}
return value;
});
-
+ const theme = useTheme();
const ExtraExtensionComponent = extraExtension?.component;
const ExtraExtensionLogo = extraExtension?.logo;
const ExtensionDescription = extraExtension?.description;
+ const allowRunAsync = isFeatureEnabled(FeatureFlag.ForceSqlLabRunAsync)
+ ? true
+ : !!db?.allow_run_async;
+ const isAllowRunAsyncDisabled = isFeatureEnabled(
+ FeatureFlag.ForceSqlLabRunAsync,
+ );
return (
<Collapse
@@ -319,7 +328,7 @@ const ExtraOptions = ({
<IndeterminateCheckbox
id="allow_run_async"
indeterminate={false}
- checked={!!db?.allow_run_async}
+ checked={allowRunAsync}
onChange={onInputChange}
labelText={t('Asynchronous query execution')}
/>
@@ -331,6 +340,14 @@ const ExtraOptions = ({
'backend. Refer to the installation docs for more information.',
)}
/>
+ {isAllowRunAsyncDisabled && (
+ <InfoTooltip
+ iconStyle={{ color: theme.colors.error.base }}
+ tooltip={t(
+ 'This option has been disabled by the administrator.',
+ )}
+ />
+ )}
</div>
</StyledInputContainer>
<StyledInputContainer css={{ no_margin_bottom }}>
diff --git a/superset/config.py b/superset/config.py
index d3a4694a03..8256ca0dc0 100644
--- a/superset/config.py
+++ b/superset/config.py
@@ -537,6 +537,8 @@ DEFAULT_FEATURE_FLAGS: dict[str, bool] = {
"PLAYWRIGHT_REPORTS_AND_THUMBNAILS": False,
# Set to True to enable experimental chart plugins
"CHART_PLUGINS_EXPERIMENTAL": False,
+ # Regardless of database configuration settings, force SQLLAB to run async using Celery
+ "SQLLAB_FORCE_RUN_ASYNC": False,
}
# ------------------------------
diff --git a/superset/sqllab/sqllab_execution_context.py b/superset/sqllab/sqllab_execution_context.py
index f67e2bf5a9..5ca180d101 100644
--- a/superset/sqllab/sqllab_execution_context.py
+++ b/superset/sqllab/sqllab_execution_context.py
@@ -77,7 +77,9 @@ class SqlJsonExecutionContext: # pylint: disable=too-many-instance-attributes
self.schema = cast(str, query_params.get("schema"))
self.sql = cast(str, query_params.get("sql"))
self.template_params = self._get_template_params(query_params)
- self.async_flag = cast(bool, query_params.get("runAsync"))
+ self.async_flag = is_feature_enabled("SQLLAB_FORCE_RUN_ASYNC") or cast(
+ bool, query_params.get("runAsync")
+ )
self.limit = self._get_limit_param(query_params)
self.status = cast(str, query_params.get("status"))
if cast(bool, query_params.get("select_as_cta")):
diff --git a/tests/unit_tests/sql_lab_execution_context.py b/tests/unit_tests/sql_lab_execution_context.py
new file mode 100644
index 0000000000..ea39e2bf3d
--- /dev/null
+++ b/tests/unit_tests/sql_lab_execution_context.py
@@ -0,0 +1,96 @@
+# 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.
+# pylint: disable=import-outside-toplevel, invalid-name, unused-argument, too-many-locals
+
+import pytest
+
+from superset.sqllab.sqllab_execution_context import (
+ CreateTableAsSelect,
+ SqlJsonExecutionContext,
+)
+from tests.unit_tests.conftest import with_feature_flags
+
+
+@pytest.fixture
+def query_params():
+ return {
+ "database_id": 1,
+ "catalog": "default",
+ "schema": "public",
+ "sql": "SELECT * FROM table",
+ "templateParams": "{}",
+ "runAsync": False,
+ "queryLimit": 1000,
+ "status": "success",
+ "select_as_cta": False,
+ "client_id": "client123",
+ "sql_editor_id": "editor123",
+ "tab": "tab123",
+ "expand_data": False,
+ }
+
+
+def test_sql_json_execution_context_init(query_params):
+ context = SqlJsonExecutionContext(query_params)
+ assert context.database_id == 1
+ assert context.catalog == "default"
+ assert context.schema == "public"
+ assert context.sql == "SELECT * FROM table"
+ assert context.template_params == {}
+ assert context.async_flag is False
+ assert context.limit == 1000
+ assert context.status == "success"
+ assert context.client_id == "client123"
+ assert context.sql_editor_id == "editor123"
+ assert context.tab_name == "tab123"
+ assert context.expand_data is False
+
+
+@with_feature_flags(SQLLAB_FORCE_RUN_ASYNC=True)
+@pytest.mark.parametrize("runAsync, expected_async_flag", [(True, True), (False, True)])
+def test_sql_json_execution_context_feature_flag_false(
+ mocker, query_params, runAsync, expected_async_flag
+):
+ query_params["runAsync"] = runAsync
+ context = SqlJsonExecutionContext(query_params)
+ assert context.async_flag == expected_async_flag
+ assert context.is_run_asynchronous() == expected_async_flag
+
+
+@with_feature_flags(SQLLAB_FORCE_RUN_ASYNC=False)
+@pytest.mark.parametrize(
+ "runAsync, expected_async_flag", [(True, True), (False, False)]
+)
+def test_sql_json_execution_context_feature_flag_true(
+ mocker, query_params, runAsync, expected_async_flag
+):
+ query_params["runAsync"] = runAsync
+ context = SqlJsonExecutionContext(query_params)
+ assert context.async_flag == expected_async_flag
+ assert context.is_run_asynchronous() == expected_async_flag
+
+
+def test_create_table_as_select():
+ query_params = {
+ "ctas_method": "TABLE",
+ "schema": "public",
+ "tmp_table_name": "temp_table",
+ }
+ ctas = CreateTableAsSelect.create_from(query_params)
+ assert ctas.ctas_method == "TABLE"
+ assert ctas.target_schema_name == "public"
+ assert ctas.target_table_name == "temp_table"