fix(mysql): reuse data tab client session
This commit is contained in:
parent
8a30bb26f9
commit
3ff4f470f2
|
|
@ -2555,9 +2555,9 @@ export const useQueryStore = defineStore("query", () => {
|
|||
executionPromise = api.executeInManualTransaction(tab.txnSessionId, sqlToExecute, tab.database, executionSchema, pageLimit);
|
||||
} else {
|
||||
console.info("[DBX][executeTabSql:execute-multi:start]", { traceId, elapsed: elapsed() });
|
||||
// Data tabs should reuse the already-open pool; session pools are reserved
|
||||
// for query tabs/background tasks that need connection-local state isolation.
|
||||
const clientSessionId = tab.mode === "query" ? tabClientSessionId(tab) : undefined;
|
||||
// Query and data tabs use a tab-scoped pool so repeated executions keep
|
||||
// connection-local state and avoid MySQL pool resets on every refresh.
|
||||
const clientSessionId = tab.mode === "query" || tab.mode === "data" ? tabClientSessionId(tab) : undefined;
|
||||
const executionOptions = {
|
||||
...(typeof pageLimit === "number"
|
||||
? useAgentResultSession
|
||||
|
|
|
|||
|
|
@ -3515,7 +3515,7 @@ test("query execution is scoped to the tab client session", async () => {
|
|||
}
|
||||
});
|
||||
|
||||
test("data tab execution reuses the shared connection pool", async () => {
|
||||
test("data tab execution uses a tab-scoped client session", async () => {
|
||||
const restoreStorage = installMemoryStorage();
|
||||
setActivePinia(createPinia());
|
||||
const connectionStore = useConnectionStore();
|
||||
|
|
@ -3541,7 +3541,7 @@ test("data tab execution reuses the shared connection pool", async () => {
|
|||
try {
|
||||
await store.executeTabSql(tabId, "select * from users");
|
||||
|
||||
assert.equal(executeBody.clientSessionId, undefined);
|
||||
assert.equal(executeBody.clientSessionId, tabId);
|
||||
assert.equal(executeBody.timeoutSecs, 30);
|
||||
} finally {
|
||||
globalThis.fetch = originalFetch;
|
||||
|
|
@ -3549,6 +3549,55 @@ test("data tab execution reuses the shared connection pool", async () => {
|
|||
}
|
||||
});
|
||||
|
||||
test("closing a data tab releases its tab-scoped client session", async () => {
|
||||
const restoreStorage = installMemoryStorage();
|
||||
setActivePinia(createPinia());
|
||||
const connectionStore = useConnectionStore();
|
||||
const store = useQueryStore();
|
||||
const originalFetch = globalThis.fetch;
|
||||
|
||||
connectionStore.addEphemeralConnection(conn("conn-1"));
|
||||
const tabId = store.createTab("conn-1", "db", "users", "data", "public");
|
||||
let executeBody: any;
|
||||
const closedSessions: any[] = [];
|
||||
|
||||
globalThis.fetch = withConnectionHealthMock(async (input, init) => {
|
||||
const url = String(input);
|
||||
if (url === "/api/query/execute-multi") {
|
||||
executeBody = JSON.parse(String(init?.body ?? "{}"));
|
||||
return new Response(JSON.stringify([{ columns: ["id"], rows: [[1]], affected_rows: 0, execution_time_ms: 1 }]), {
|
||||
status: 200,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
});
|
||||
}
|
||||
if (url === "/api/query/close-client-session") {
|
||||
closedSessions.push(JSON.parse(String(init?.body ?? "{}")));
|
||||
return new Response(JSON.stringify(true), {
|
||||
status: 200,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
});
|
||||
}
|
||||
return new Response("unexpected request", { status: 500 });
|
||||
});
|
||||
|
||||
try {
|
||||
await store.executeTabSql(tabId, "select * from users");
|
||||
assert.equal(executeBody.clientSessionId, tabId);
|
||||
|
||||
store.closeTab(tabId, { force: true });
|
||||
|
||||
// closeClientConnectionSession is fire-and-forget; wait for the request to land.
|
||||
await waitFor(() => closedSessions.some((body) => body.clientSessionId === tabId));
|
||||
assert.ok(
|
||||
closedSessions.some((body) => body.clientSessionId === tabId && body.connectionId === "conn-1"),
|
||||
`expected close-client-session for tab session, got ${JSON.stringify(closedSessions)}`,
|
||||
);
|
||||
} finally {
|
||||
globalThis.fetch = originalFetch;
|
||||
restoreStorage();
|
||||
}
|
||||
});
|
||||
|
||||
test("query execution keeps automatically counting total rows in the background", async () => {
|
||||
const restoreStorage = installMemoryStorage();
|
||||
setActivePinia(createPinia());
|
||||
|
|
|
|||
|
|
@ -97,8 +97,8 @@ test("data reload executes before slow metadata refresh completes", async () =>
|
|||
const actions = useDataGridActions(computed(() => tab));
|
||||
const reload = actions.onReloadData(undefined, undefined, undefined, undefined, 50, 0);
|
||||
|
||||
await waitFor(() => !!executeBody);
|
||||
assert.equal(executeBody.clientSessionId, undefined);
|
||||
await waitFor(() => !!executeBody, 5_000);
|
||||
assert.equal(executeBody.clientSessionId, tabId);
|
||||
assert.deepEqual(tab.result?.rows, [[1]]);
|
||||
|
||||
await waitFor(() => typeof resolveColumns === "function");
|
||||
|
|
|
|||
Loading…
Reference in New Issue