Skip to content
This repository has been archived by the owner on Jun 4, 2024. It is now read-only.

[WIP] upload scheduled query metadata #504

Merged
merged 6 commits into from
Aug 3, 2018
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions app/actions/sessions.js
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,6 @@ export function createScheduledQuery(connectionId, payload = {}) {
fid: payload.fid,
filename: payload.filename,
name: payload.name,
refreshInterval: payload.refreshInterval,
query: payload.query,
cronInterval: payload.cronInterval,
connectionId
Expand All @@ -189,7 +188,6 @@ export function updateScheduledQuery(connectionId, payload = {}) {
fid: payload.fid,
filename: payload.filename,
name: payload.name,
refreshInterval: payload.refreshInterval,
query: payload.query,
cronInterval: payload.cronInterval,
connectionId
Expand Down
8 changes: 1 addition & 7 deletions app/components/Settings/scheduler/create-modal.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,7 @@ import TimedMessage from './timed-message.jsx';
import CronPicker from '../cron-picker/cron-picker.jsx';
import SQL from './sql.jsx';

import {
getHighlightMode,
DEFAULT_REFRESH_INTERVAL,
WAITING_MESSAGE,
SAVE_WARNING
} from '../../../constants/constants.js';
import {getHighlightMode, WAITING_MESSAGE, SAVE_WARNING} from '../../../constants/constants.js';

import './create-modal.css';

Expand Down Expand Up @@ -109,7 +104,6 @@ class CreateModal extends Component {
this.props
.onSubmit({
query: this.state.code,
refreshInterval: DEFAULT_REFRESH_INTERVAL,
filename: generateFilename(),
cronInterval: this.state.interval,
name: this.state.name ? this.state.name.trim() : ''
Expand Down
12 changes: 3 additions & 9 deletions app/components/Settings/scheduler/preview-modal.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,7 @@ import CronPicker from '../cron-picker/cron-picker.jsx';
import {Row, Column} from '../../layout.jsx';
import SQL from './sql.jsx';
import {plotlyUrl} from '../../../utils/utils.js';
import {
getHighlightMode,
DEFAULT_REFRESH_INTERVAL,
WAITING_MESSAGE,
SAVE_WARNING
} from '../../../constants/constants.js';
import {getHighlightMode, WAITING_MESSAGE, SAVE_WARNING} from '../../../constants/constants.js';
import {getInitialCronMode} from '../cron-picker/cron-helpers.js';

const NO_OP = () => {};
Expand Down Expand Up @@ -85,7 +80,7 @@ export class PreviewModal extends Component {

onSubmit() {
if (this.state.editing) {
const {connectionId, fid, requestor, uids, refreshInterval} = this.props.query;
const {connectionId, fid, requestor, uids} = this.props.query;
const {code: query, cronInterval} = this.state;
const name = this.state.name ? this.state.name.trim() : '';

Expand All @@ -98,8 +93,7 @@ export class PreviewModal extends Component {
uids,
query,
name,
cronInterval,
refreshInterval: refreshInterval || DEFAULT_REFRESH_INTERVAL
cronInterval
})
.then(() => {
this.setState({
Expand Down
6 changes: 0 additions & 6 deletions app/constants/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,6 @@
/* eslint-disable no-multi-str */
import {concat} from 'ramda';

/**
* Default to '1 week' for `refreshInterval` for backwards compatability. For
* older versions this will prevent issues such as `setInterval(runQuery, NaN)`
*/
export const DEFAULT_REFRESH_INTERVAL = 7 * 24 * 60 * 60;

export const DIALECTS = {
MYSQL: 'mysql',
MARIADB: 'mariadb',
Expand Down
64 changes: 54 additions & 10 deletions backend/persistent/QueryScheduler.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import * as scheduler from 'node-schedule';

import {getConnectionById} from './Connections.js';
import * as Connections from './datastores/Datastores.js';
import { mapRefreshToCron } from '../utils/cronUtils.js';
import { mapRefreshToCron, mapCronToRefresh } from '../utils/cronUtils.js';
import Logger from '../logger';
import {
getQuery,
Expand All @@ -19,6 +19,7 @@ import {
getCurrentUser,
getGridMeta,
newGrid,
patchGrid,
updateGrid
} from './plotly-api.js';

Expand Down Expand Up @@ -97,7 +98,7 @@ class QueryScheduler {
requestor,
fid,
uids,
refreshInterval,
refreshInterval: refreshInterval || mapCronToRefresh(cronInterval),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

cronInterval,
query,
connectionId
Expand Down Expand Up @@ -142,9 +143,11 @@ class QueryScheduler {
Object.keys(this.queryJobs).forEach(this.clearQuery);
}

queryAndCreateGrid(filename, query, connectionId, requestor) {
queryAndCreateGrid(filename, query, connectionId, requestor, cronInterval, refreshInterval) {
const {username, apiKey, accessToken} = getCredentials(requestor);
const formattedRefresh = refreshInterval || mapCronToRefresh(cronInterval);
let startTime;
let createdJson;

// Check if the user even exists
if (!username || !(apiKey || accessToken)) {
Expand Down Expand Up @@ -204,16 +207,38 @@ class QueryScheduler {
Logger.log(`Error ${res.status} while creating a grid`, 2);
}

return res.json().then((json) => {
Logger.log(`Grid ${json.file.fid} has been updated.`, 2);
return json;
return res.json();
}).then((json) => {
createdJson = json;
startTime = process.hrtime();

return patchGrid(
createdJson.file.fid,
requestor,
{
metadata: {
query,
connectionId,
connectorUrl: `https://${getSetting('CONNECTOR_HTTPS_DOMAIN')}:${getSetting('PORT_HTTPS')}`
},
refresh_interval: formattedRefresh
}
).catch((e) => {
/*
* Warning: The front end looks for "PlotlyApiError" in this error message. Don't change it!
*/
throw new Error(`PlotlyApiError: ${e.message}`);
});
}).then(() => {
Logger.log(`Request to Plotly for creating a grid took ${process.hrtime(startTime)[0]} seconds`, 2);
Logger.log(`Grid ${createdJson.file.fid} has been updated.`, 2);
return createdJson;
});

}

queryAndUpdateGrid(fid, uids, query, connectionId, requestor) {
queryAndUpdateGrid(fid, uids, query, connectionId, requestor, cronInterval, refreshInterval) {
const requestedDBConnections = getConnectionById(connectionId);
const formattedRefresh = refreshInterval || mapCronToRefresh(cronInterval);
let startTime = process.hrtime();

/*
Expand Down Expand Up @@ -337,13 +362,32 @@ class QueryScheduler {

}

startTime = process.hrtime();

return patchGrid(
fid,
requestor,
{
metadata: {
query,
connectionId,
connectorUrl: `https://${getSetting('CONNECTOR_HTTPS_DOMAIN')}:${getSetting('PORT_HTTPS')}`
},
refresh_interval: formattedRefresh
}
).catch((e) => {
/*
* Warning: The front end looks for "PlotlyApiError" in this error message. Don't change it!
*/
throw new Error(`PlotlyApiError: ${e.message}`);
});
}).then((res) => {
Logger.log(`Request to Plotly for creating a grid took ${process.hrtime(startTime)[0]} seconds`, 2);
return res.json().then(() => {
Logger.log(`Grid ${fid} has been updated.`, 2);
});
});

}

}

export default QueryScheduler;
Expand Down
12 changes: 12 additions & 0 deletions backend/persistent/plotly-api.js
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,18 @@ export function deleteGrid(fid, requestor) {
});
}

export function patchGrid(fid, requestor, body) {
const {username, apiKey, accessToken} = getCredentials(requestor);

return plotlyAPIRequest(`grids/${fid}`, {
method: 'PATCH',
username,
apiKey,
accessToken,
body
});
}

export function updateGrid(rows, fid, uids, requestor) {
const {username, apiKey, accessToken} = getCredentials(requestor);

Expand Down
15 changes: 12 additions & 3 deletions backend/routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -664,13 +664,22 @@ export default class Servers {
* the endpoint `/queries/:fid`
*/
server.post('/queries', function postQueriesHandler(req, res, next) {
const {filename, fid, uids, query, connectionId, requestor} = req.params;
const {
filename,
fid,
uids,
query,
connectionId,
requestor,
cronInterval = null,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

out of curiosity, why setting the default to 'null'?

refreshInterval = null
} = req.params;

// If a filename has been provided,
// make the query and create a new grid
if (filename) {
return that.queryScheduler.queryAndCreateGrid(
filename, query, connectionId, requestor
filename, query, connectionId, requestor, cronInterval, refreshInterval
)
.then((newGridResponse) => {
const queryObject = {
Expand All @@ -691,7 +700,7 @@ export default class Servers {
if (fid) {
return checkWritePermissions(fid, requestor).then(function () {
return that.queryScheduler.queryAndUpdateGrid(
fid, uids, query, connectionId, requestor
fid, uids, query, connectionId, requestor, cronInterval, refreshInterval
);
})
.then(() => {
Expand Down
20 changes: 20 additions & 0 deletions backend/utils/cronUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,26 @@ export function mapRefreshToCron (refreshInterval) {
return `${now.getMinutes()} ${now.getHours()} * * ${now.getDay()}`;
}

export function mapCronToRefresh (cronInterval) {
const DEFAULT_INTERVAL = 60 * 60 * 24 * 7; // default to weekly

if (!cronInterval) {
return DEFAULT_INTERVAL;
}

if (cronInterval === '* * * * *') {
return 60;
} else if (cronInterval === '*/5 * * * *') {
return 60 * 5;
} else if (cronInterval.match(/\S+? \* \* \* \*/)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this throws when cronInterval is null

return 60 * 60;
} else if (cronInterval.match(/\S+? \S+? \* \* \*/)) {
return 60 * 60 * 24;
}

return DEFAULT_INTERVAL;
}

function computeMinutes (now) {
let currMinute = now.getMinutes() % 5; // start at 5 min offset
const minutes = [];
Expand Down