Change query processing wait time to make response quick (#7320)

* Change query processing wait time to make more response quick

* Fix styling errors reportered by restyled
This commit is contained in:
Tsuneo Yoshioka
2025-05-07 10:22:35 +09:00
committed by GitHub
parent 5d31429ca8
commit 0900178d24

View File

@@ -9,7 +9,7 @@ const logger = debug("redash:services:QueryResult");
const filterTypes = ["filter", "multi-filter", "multiFilter"]; const filterTypes = ["filter", "multi-filter", "multiFilter"];
function defer() { function defer() {
const result = { onStatusChange: status => {} }; const result = { onStatusChange: (status) => {} };
result.promise = new Promise((resolve, reject) => { result.promise = new Promise((resolve, reject) => {
result.resolve = resolve; result.resolve = resolve;
result.reject = reject; result.reject = reject;
@@ -40,13 +40,13 @@ function getColumnNameWithoutType(column) {
} }
function getColumnFriendlyName(column) { function getColumnFriendlyName(column) {
return getColumnNameWithoutType(column).replace(/(?:^|\s)\S/g, a => a.toUpperCase()); return getColumnNameWithoutType(column).replace(/(?:^|\s)\S/g, (a) => a.toUpperCase());
} }
const createOrSaveUrl = data => (data.id ? `api/query_results/${data.id}` : "api/query_results"); const createOrSaveUrl = (data) => (data.id ? `api/query_results/${data.id}` : "api/query_results");
const QueryResultResource = { const QueryResultResource = {
get: ({ id }) => axios.get(`api/query_results/${id}`), get: ({ id }) => axios.get(`api/query_results/${id}`),
post: data => axios.post(createOrSaveUrl(data), data), post: (data) => axios.post(createOrSaveUrl(data), data),
}; };
export const ExecutionStatus = { export const ExecutionStatus = {
@@ -97,11 +97,11 @@ function handleErrorResponse(queryResult, error) {
} }
function sleep(ms) { function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms)); return new Promise((resolve) => setTimeout(resolve, ms));
} }
export function fetchDataFromJob(jobId, interval = 1000) { export function fetchDataFromJob(jobId, interval = 1000) {
return axios.get(`api/jobs/${jobId}`).then(data => { return axios.get(`api/jobs/${jobId}`).then((data) => {
const status = statuses[data.job.status]; const status = statuses[data.job.status];
if (status === ExecutionStatus.WAITING || status === ExecutionStatus.PROCESSING) { if (status === ExecutionStatus.WAITING || status === ExecutionStatus.PROCESSING) {
return sleep(interval).then(() => fetchDataFromJob(data.job.id)); return sleep(interval).then(() => fetchDataFromJob(data.job.id));
@@ -146,7 +146,7 @@ class QueryResult {
// TODO: we should stop manipulating incoming data, and switch to relaying // TODO: we should stop manipulating incoming data, and switch to relaying
// on the column type set by the backend. This logic is prone to errors, // on the column type set by the backend. This logic is prone to errors,
// and better be removed. Kept for now, for backward compatability. // and better be removed. Kept for now, for backward compatability.
each(this.query_result.data.rows, row => { each(this.query_result.data.rows, (row) => {
forOwn(row, (v, k) => { forOwn(row, (v, k) => {
let newType = null; let newType = null;
if (isNumber(v)) { if (isNumber(v)) {
@@ -173,7 +173,7 @@ class QueryResult {
}); });
}); });
each(this.query_result.data.columns, column => { each(this.query_result.data.columns, (column) => {
column.name = "" + column.name; column.name = "" + column.name;
if (columnTypes[column.name]) { if (columnTypes[column.name]) {
if (column.type == null || column.type === "string") { if (column.type == null || column.type === "string") {
@@ -265,14 +265,14 @@ class QueryResult {
getColumnNames() { getColumnNames() {
if (this.columnNames === undefined && this.query_result.data) { if (this.columnNames === undefined && this.query_result.data) {
this.columnNames = this.query_result.data.columns.map(v => v.name); this.columnNames = this.query_result.data.columns.map((v) => v.name);
} }
return this.columnNames; return this.columnNames;
} }
getColumnFriendlyNames() { getColumnFriendlyNames() {
return this.getColumnNames().map(col => getColumnFriendlyName(col)); return this.getColumnNames().map((col) => getColumnFriendlyName(col));
} }
getTruncated() { getTruncated() {
@@ -286,7 +286,7 @@ class QueryResult {
const filters = []; const filters = [];
this.getColumns().forEach(col => { this.getColumns().forEach((col) => {
const name = col.name; const name = col.name;
const type = name.split("::")[1] || name.split("__")[1]; const type = name.split("::")[1] || name.split("__")[1];
if (includes(filterTypes, type)) { if (includes(filterTypes, type)) {
@@ -302,8 +302,8 @@ class QueryResult {
} }
}, this); }, this);
this.getRawData().forEach(row => { this.getRawData().forEach((row) => {
filters.forEach(filter => { filters.forEach((filter) => {
filter.values.push(row[filter.name]); filter.values.push(row[filter.name]);
if (filter.values.length === 1) { if (filter.values.length === 1) {
if (filter.multiple) { if (filter.multiple) {
@@ -315,8 +315,8 @@ class QueryResult {
}); });
}); });
filters.forEach(filter => { filters.forEach((filter) => {
filter.values = uniqBy(filter.values, v => { filter.values = uniqBy(filter.values, (v) => {
if (moment.isMoment(v)) { if (moment.isMoment(v)) {
return v.unix(); return v.unix();
} }
@@ -345,12 +345,12 @@ class QueryResult {
axios axios
.get(`api/queries/${queryId}/results/${id}.json`) .get(`api/queries/${queryId}/results/${id}.json`)
.then(response => { .then((response) => {
// Success handler // Success handler
queryResult.isLoadingResult = false; queryResult.isLoadingResult = false;
queryResult.update(response); queryResult.update(response);
}) })
.catch(error => { .catch((error) => {
// Error handler // Error handler
queryResult.isLoadingResult = false; queryResult.isLoadingResult = false;
handleErrorResponse(queryResult, error); handleErrorResponse(queryResult, error);
@@ -362,10 +362,10 @@ class QueryResult {
loadLatestCachedResult(queryId, parameters) { loadLatestCachedResult(queryId, parameters) {
axios axios
.post(`api/queries/${queryId}/results`, { queryId, parameters }) .post(`api/queries/${queryId}/results`, { queryId, parameters })
.then(response => { .then((response) => {
this.update(response); this.update(response);
}) })
.catch(error => { .catch((error) => {
handleErrorResponse(this, error); handleErrorResponse(this, error);
}); });
} }
@@ -375,11 +375,11 @@ class QueryResult {
this.deferred.onStatusChange(ExecutionStatus.LOADING_RESULT); this.deferred.onStatusChange(ExecutionStatus.LOADING_RESULT);
QueryResultResource.get({ id: this.job.query_result_id }) QueryResultResource.get({ id: this.job.query_result_id })
.then(response => { .then((response) => {
this.update(response); this.update(response);
this.isLoadingResult = false; this.isLoadingResult = false;
}) })
.catch(error => { .catch((error) => {
if (tryCount === undefined) { if (tryCount === undefined) {
tryCount = 0; tryCount = 0;
} }
@@ -394,9 +394,12 @@ class QueryResult {
}); });
this.isLoadingResult = false; this.isLoadingResult = false;
} else { } else {
setTimeout(() => { setTimeout(
this.loadResult(tryCount + 1); () => {
}, 1000 * Math.pow(2, tryCount)); this.loadResult(tryCount + 1);
},
1000 * Math.pow(2, tryCount)
);
} }
}); });
} }
@@ -410,19 +413,26 @@ class QueryResult {
: axios.get(`api/queries/${query}/jobs/${this.job.id}`); : axios.get(`api/queries/${query}/jobs/${this.job.id}`);
request request
.then(jobResponse => { .then((jobResponse) => {
this.update(jobResponse); this.update(jobResponse);
if (this.getStatus() === "processing" && this.job.query_result_id && this.job.query_result_id !== "None") { if (this.getStatus() === "processing" && this.job.query_result_id && this.job.query_result_id !== "None") {
loadResult(); loadResult();
} else if (this.getStatus() !== "failed") { } else if (this.getStatus() !== "failed") {
const waitTime = tryNumber > 10 ? 3000 : 500; let waitTime;
if (tryNumber <= 10) {
waitTime = 500;
} else if (tryNumber <= 50) {
waitTime = 1000;
} else {
waitTime = 3000;
}
setTimeout(() => { setTimeout(() => {
this.refreshStatus(query, parameters, tryNumber + 1); this.refreshStatus(query, parameters, tryNumber + 1);
}, waitTime); }, waitTime);
} }
}) })
.catch(error => { .catch((error) => {
logger("Connection error", error); logger("Connection error", error);
// TODO: use QueryResultError, or better yet: exception/reject of promise. // TODO: use QueryResultError, or better yet: exception/reject of promise.
this.update({ this.update({
@@ -451,14 +461,14 @@ class QueryResult {
axios axios
.post(`api/queries/${id}/results`, { id, parameters, apply_auto_limit: applyAutoLimit, max_age: maxAge }) .post(`api/queries/${id}/results`, { id, parameters, apply_auto_limit: applyAutoLimit, max_age: maxAge })
.then(response => { .then((response) => {
queryResult.update(response); queryResult.update(response);
if ("job" in response) { if ("job" in response) {
queryResult.refreshStatus(id, parameters); queryResult.refreshStatus(id, parameters);
} }
}) })
.catch(error => { .catch((error) => {
handleErrorResponse(queryResult, error); handleErrorResponse(queryResult, error);
}); });
@@ -481,14 +491,14 @@ class QueryResult {
} }
QueryResultResource.post(params) QueryResultResource.post(params)
.then(response => { .then((response) => {
queryResult.update(response); queryResult.update(response);
if ("job" in response) { if ("job" in response) {
queryResult.refreshStatus(query, parameters); queryResult.refreshStatus(query, parameters);
} }
}) })
.catch(error => { .catch((error) => {
handleErrorResponse(queryResult, error); handleErrorResponse(queryResult, error);
}); });