-
Notifications
You must be signed in to change notification settings - Fork 13.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: Scheduling queries from SQL Lab #7416
Changes from all commits
c605d33
1372eff
bc03883
5af5c94
393bc42
3e953a3
a3ed2cb
0047762
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -816,6 +816,84 @@ in this dictionary are made available for users to use in their SQL. | |
'my_crazy_macro': lambda x: x*2, | ||
} | ||
|
||
**Scheduling queries** | ||
|
||
You can optionally allow your users to schedule queries directly in SQL Lab. | ||
This is done by addding extra metadata to saved queries, which are then picked | ||
up by an external scheduled (like [Apache Airflow](https://airflow.apache.org/)). | ||
|
||
To allow scheduled queries, add the following to your `config.py`: | ||
|
||
.. code-block:: python | ||
|
||
FEATURE_FLAGS = { | ||
# Configuration for scheduling queries from SQL Lab. This information is | ||
# collected when the user clicks "Schedule query", and saved into the `extra` | ||
# field of saved queries. | ||
# See: https://github.com/mozilla-services/react-jsonschema-form | ||
'SCHEDULED_QUERIES': { | ||
'JSONSCHEMA': { | ||
'title': 'Schedule', | ||
'description': ( | ||
'In order to schedule a query, you need to specify when it ' | ||
'should start running, when it should stop running, and how ' | ||
'often it should run. You can also optionally specify ' | ||
'dependencies that should be met before the query is ' | ||
'executed. Please read the documentation for best practices ' | ||
'and more information on how to specify dependencies.' | ||
), | ||
'type': 'object', | ||
'properties': { | ||
'output_table': { | ||
'type': 'string', | ||
'title': 'Output table name', | ||
}, | ||
'start_date': { | ||
'type': 'string', | ||
'format': 'date-time', | ||
'title': 'Start date', | ||
}, | ||
'end_date': { | ||
'type': 'string', | ||
'format': 'date-time', | ||
'title': 'End date', | ||
}, | ||
'schedule_interval': { | ||
'type': 'string', | ||
'title': 'Schedule interval', | ||
}, | ||
'dependencies': { | ||
'type': 'array', | ||
'title': 'Dependencies', | ||
'items': { | ||
'type': 'string', | ||
}, | ||
}, | ||
}, | ||
}, | ||
'UISCHEMA': { | ||
'schedule_interval': { | ||
'ui:placeholder': '@daily, @weekly, etc.', | ||
}, | ||
'dependencies': { | ||
'ui:help': ( | ||
'Check the documentation for the correct format when ' | ||
'defining dependencies.' | ||
), | ||
}, | ||
}, | ||
}, | ||
} | ||
|
||
This feature flag is based on [react-jsonschema-form](https://github.com/mozilla-services/react-jsonschema-form), | ||
and will add a button called "Schedule Query" to SQL Lab. When the button is | ||
clicked, a modal will show up where the user can add the metadata required for | ||
scheduling the query. | ||
|
||
This information can then be retrieved from the endpoint `/savedqueryviewapi/api/read` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. point of curiosity: Is this URL something we have control over? (I don't see it specified anywhere, so I assume generated from a base class). It feels like a more idiomatic "RESTful" URL for a platform-y backend would be There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's automatically generated by FAB. There's a view called |
||
and used to schedule the queries that have `scheduled_queries` in their JSON | ||
metadata. For schedulers other than Airflow, additional fields can be easily | ||
added to the configuration file above. | ||
|
||
Celery Flower | ||
------------- | ||
|
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
/** | ||
* 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. | ||
*/ | ||
import React from 'react'; | ||
import PropTypes from 'prop-types'; | ||
import Form from 'react-jsonschema-form'; | ||
import { t } from '@superset-ui/translation'; | ||
|
||
import Button from '../../components/Button'; | ||
import ModalTrigger from '../../components/ModalTrigger'; | ||
|
||
const propTypes = { | ||
defaultLabel: PropTypes.string, | ||
sql: PropTypes.string.isRequired, | ||
schema: PropTypes.string.isRequired, | ||
dbId: PropTypes.number.isRequired, | ||
animation: PropTypes.bool, | ||
onSchedule: PropTypes.func, | ||
}; | ||
const defaultProps = { | ||
defaultLabel: t('Undefined'), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we provide default values for the other props? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah, good point. I'll mark the other ones as required (sql, schema, dbid). |
||
animation: true, | ||
onSchedule: () => {}, | ||
}; | ||
|
||
class ScheduleQueryButton extends React.PureComponent { | ||
constructor(props) { | ||
super(props); | ||
this.state = { | ||
description: '', | ||
label: props.defaultLabel, | ||
showSchedule: false, | ||
}; | ||
this.toggleSchedule = this.toggleSchedule.bind(this); | ||
this.onSchedule = this.onSchedule.bind(this); | ||
this.onCancel = this.onCancel.bind(this); | ||
this.onLabelChange = this.onLabelChange.bind(this); | ||
this.onDescriptionChange = this.onDescriptionChange.bind(this); | ||
} | ||
onSchedule({ formData }) { | ||
const query = { | ||
label: this.state.label, | ||
description: this.state.description, | ||
db_id: this.props.dbId, | ||
schema: this.props.schema, | ||
sql: this.props.sql, | ||
extra_json: JSON.stringify({ schedule_info: formData }), | ||
}; | ||
this.props.onSchedule(query); | ||
this.saveModal.close(); | ||
} | ||
onCancel() { | ||
this.saveModal.close(); | ||
} | ||
onLabelChange(e) { | ||
this.setState({ label: e.target.value }); | ||
} | ||
onDescriptionChange(e) { | ||
this.setState({ description: e.target.value }); | ||
} | ||
toggleSchedule(e) { | ||
this.setState({ target: e.target, showSchedule: !this.state.showSchedule }); | ||
} | ||
renderModalBody() { | ||
return ( | ||
<Form | ||
schema={window.featureFlags.SCHEDULED_QUERIES.JSONSCHEMA} | ||
uiSchema={window.featureFlags.SCHEDULED_QUERIES.UISCHEMA} | ||
onSubmit={this.onSchedule} | ||
/> | ||
); | ||
} | ||
render() { | ||
return ( | ||
<span className="ScheduleQueryButton"> | ||
<ModalTrigger | ||
ref={(ref) => { this.saveModal = ref; }} | ||
modalTitle={t('Schedule Query')} | ||
modalBody={this.renderModalBody()} | ||
triggerNode={ | ||
<Button bsSize="small" className="toggleSchedule" onClick={this.toggleSchedule}> | ||
<i className="fa fa-calendar" /> {t('Schedule Query')} | ||
</Button> | ||
} | ||
bsSize="medium" | ||
/> | ||
</span> | ||
); | ||
} | ||
} | ||
ScheduleQueryButton.propTypes = propTypes; | ||
ScheduleQueryButton.defaultProps = defaultProps; | ||
|
||
export default ScheduleQueryButton; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bumped into an error today where the SQL Lab page fails to render because somehow I set
FEATURE_FLAGS['SCHEDULED_QUERIES']
toTrue
in my local configs.It is a surprise to me that complex objects are added into "flags". I thought it's only about on/off toggles. This is quite confusing and would make it difficult to extend the
FEATURE_FLAGS
feature structurally (say, moving the management of it to the database or an external API).Can we maybe introduce a new config value
SCHEDULED_QUERIES_SCHEMA
and keepFEATURE_FLAGS
simple?