mirror of
https://github.com/t8y2/dbx.git
synced 2026-10-19 16:16:45 +00:00
fix(query): stop doubling global query timeout
This commit is contained in:
+6
-5
@@ -29,17 +29,18 @@ describe("queryTimeout", () => {
|
||||
const packageSpec = `CREATE OR REPLACE PACKAGE pkg_utils AS
|
||||
FUNCTION get_version RETURN VARCHAR2;
|
||||
END pkg_utils;`;
|
||||
expect(frontendQueryTimeoutSecsForSql(`${packageSpec}\n/\nSELECT 1;`, "opengauss", 30)).toBe(120);
|
||||
expect(frontendQueryTimeoutSecsForSql(`${packageSpec}\n/\nSELECT 1;`, "opengauss", 30)).toBe(60);
|
||||
});
|
||||
|
||||
it("keeps the frontend guard for non-row PostgreSQL statements", () => {
|
||||
expect(frontendQueryTimeoutSecsForSql("UPDATE sample_records SET state = 'ready'", "postgres", 30)).toBe(60);
|
||||
expect(frontendQueryTimeoutSecsForSql("INSERT INTO sample_records(note) VALUES ('RETURNING is text')", "postgres", 30)).toBe(60);
|
||||
expect(frontendQueryTimeoutSecsForSql("UPDATE sample_records SET note = 'ready' /* RETURNING */", "postgres", 30)).toBe(60);
|
||||
expect(frontendQueryTimeoutSecsForSql("UPDATE sample_records SET state = 'ready'", "postgres", 30)).toBe(30);
|
||||
expect(frontendQueryTimeoutSecsForSql("INSERT INTO sample_records(note) VALUES ('RETURNING is text')", "postgres", 30)).toBe(30);
|
||||
expect(frontendQueryTimeoutSecsForSql("UPDATE sample_records SET note = 'ready' /* RETURNING */", "postgres", 30)).toBe(30);
|
||||
});
|
||||
|
||||
it("keeps the existing frontend guard for other database types", () => {
|
||||
expect(frontendQueryTimeoutSecsForSql("SELECT * FROM sample_records LIMIT 2000", "mysql", 30)).toBe(60);
|
||||
expect(frontendQueryTimeoutSecsForSql("SELECT * FROM sample_records LIMIT 2000", "mysql", 30)).toBe(30);
|
||||
expect(frontendQueryTimeoutSecsForSql("SELECT SLEEP(30)", "mysql", 10)).toBe(10);
|
||||
expect(queryTimeoutSecsForConnection({ query_timeout_secs: undefined })).toBe(60);
|
||||
});
|
||||
|
||||
|
||||
@@ -56,9 +56,8 @@ export function frontendQueryTimeoutSecsForSql(sql: string, databaseType: Databa
|
||||
// the timeout for row-returning PostgreSQL statements.
|
||||
if (databaseType === "postgres" && postgresQueryMayReturnRows(sql, databaseType)) return 0;
|
||||
|
||||
const baseTimeoutSecs = Math.max(queryTimeoutSecs * 2, 60);
|
||||
const statementCount = Math.max(splitSqlStatementRanges(sql, databaseType, parameterOptions ?? sqlStatementParameterOptionsForCompatibility(databaseType)).length, 1);
|
||||
return baseTimeoutSecs * statementCount;
|
||||
return queryTimeoutSecs * statementCount;
|
||||
}
|
||||
|
||||
export function frontendQueryTimeoutDelayMs(timeoutSecs: number): number | undefined {
|
||||
|
||||
@@ -593,7 +593,7 @@ function displayedQueryMetadataSql(tab: QueryTab, fallbackSql: string): string {
|
||||
return tab.results?.length ? (tab.result?.sourceStatement ?? fallbackSql) : fallbackSql;
|
||||
}
|
||||
|
||||
async function withFrontendQueryTimeout<T>(promise: Promise<T>, timeoutSecs: number, message: string): Promise<T> {
|
||||
async function withFrontendQueryTimeout<T>(promise: Promise<T>, timeoutSecs: number, message: string, onTimeout?: () => void): Promise<T> {
|
||||
const timeoutMs = frontendQueryTimeoutDelayMs(timeoutSecs);
|
||||
if (timeoutMs === undefined) return promise;
|
||||
|
||||
@@ -602,7 +602,10 @@ async function withFrontendQueryTimeout<T>(promise: Promise<T>, timeoutSecs: num
|
||||
return await Promise.race([
|
||||
promise,
|
||||
new Promise<never>((_, reject) => {
|
||||
timer = setTimeout(() => reject(new Error(message)), timeoutMs);
|
||||
timer = setTimeout(() => {
|
||||
onTimeout?.();
|
||||
reject(new Error(message));
|
||||
}, timeoutMs);
|
||||
}),
|
||||
]);
|
||||
} finally {
|
||||
@@ -7096,7 +7099,11 @@ export const useQueryStore = defineStore("query", () => {
|
||||
executionPromise = executeWithoutManualTransaction();
|
||||
}
|
||||
const annotatedResults = annotateQueryResultSources(
|
||||
markQueryResultsRowsRaw(await withFrontendQueryTimeout(executionPromise, frontendTimeoutSecs, t("editor.queryTimeoutError", { seconds: frontendTimeoutSecs }))),
|
||||
markQueryResultsRowsRaw(
|
||||
await withFrontendQueryTimeout(executionPromise, frontendTimeoutSecs, t("editor.queryTimeoutError", { seconds: frontendTimeoutSecs }), () => {
|
||||
void api.cancelQuery(executionId).catch((error) => queryExecutionLog("warn", "frontend-timeout:cancel-failed", { traceId, error }));
|
||||
}),
|
||||
),
|
||||
queryBaseSql,
|
||||
sourceLabelDatabase,
|
||||
effectiveDbType,
|
||||
|
||||
+4
-4
@@ -14,10 +14,10 @@ test("queryTimeoutSecsForConnection falls back to the default timeout", () => {
|
||||
});
|
||||
|
||||
test("frontend query timeout scales with SQL statement count", () => {
|
||||
assert.equal(frontendQueryTimeoutSecsForSql("INSERT INTO users VALUES (1)", "mysql", 30), 60);
|
||||
assert.equal(frontendQueryTimeoutSecsForSql("INSERT INTO users VALUES (1); INSERT INTO users VALUES (2);", "mysql", 30), 120);
|
||||
assert.equal(frontendQueryTimeoutSecsForSql("INSERT INTO users VALUES (1); INSERT INTO users VALUES (2); INSERT INTO users VALUES (3);", "mysql", 10), 180);
|
||||
assert.equal(frontendQueryTimeoutSecsForSql("/* prep */\nINSERT INTO users VALUES (1);\n-- keep batching\nINSERT INTO users VALUES (2);", "mysql", 30), 120);
|
||||
assert.equal(frontendQueryTimeoutSecsForSql("INSERT INTO users VALUES (1)", "mysql", 30), 30);
|
||||
assert.equal(frontendQueryTimeoutSecsForSql("INSERT INTO users VALUES (1); INSERT INTO users VALUES (2);", "mysql", 30), 60);
|
||||
assert.equal(frontendQueryTimeoutSecsForSql("INSERT INTO users VALUES (1); INSERT INTO users VALUES (2); INSERT INTO users VALUES (3);", "mysql", 10), 30);
|
||||
assert.equal(frontendQueryTimeoutSecsForSql("/* prep */\nINSERT INTO users VALUES (1);\n-- keep batching\nINSERT INTO users VALUES (2);", "mysql", 30), 60);
|
||||
assert.equal(frontendQueryTimeoutSecsForSql("INSERT INTO users VALUES (1); INSERT INTO users VALUES (2);", "mysql", 0), 0);
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user