fix(web): use cached session lists on session detail
This commit is contained in:
parent
406b26e837
commit
408cb4571b
|
|
@ -114,7 +114,7 @@ describe("SessionPage project polling", () => {
|
|||
} as Response;
|
||||
}
|
||||
|
||||
if (url === "/api/sessions?fresh=true") {
|
||||
if (url === "/api/sessions") {
|
||||
return {
|
||||
ok: true,
|
||||
status: 200,
|
||||
|
|
@ -122,7 +122,7 @@ describe("SessionPage project polling", () => {
|
|||
} as Response;
|
||||
}
|
||||
|
||||
if (url === "/api/sessions?project=my-app&orchestratorOnly=true&fresh=true") {
|
||||
if (url === "/api/sessions?project=my-app&orchestratorOnly=true") {
|
||||
return {
|
||||
ok: true,
|
||||
status: 200,
|
||||
|
|
@ -156,12 +156,12 @@ describe("SessionPage project polling", () => {
|
|||
expect.any(Object),
|
||||
);
|
||||
expect(fetch).toHaveBeenCalledWith(
|
||||
"/api/sessions?fresh=true",
|
||||
"/api/sessions",
|
||||
expect.any(Object),
|
||||
);
|
||||
|
||||
expect(fetch).toHaveBeenCalledWith(
|
||||
"/api/sessions?project=my-app&orchestratorOnly=true&fresh=true",
|
||||
"/api/sessions?project=my-app&orchestratorOnly=true",
|
||||
expect.any(Object),
|
||||
);
|
||||
|
||||
|
|
@ -169,7 +169,7 @@ describe("SessionPage project polling", () => {
|
|||
vi
|
||||
.mocked(fetch)
|
||||
.mock.calls.filter(
|
||||
([url]) => url === "/api/sessions?project=my-app&orchestratorOnly=true&fresh=true",
|
||||
([url]) => url === "/api/sessions?project=my-app&orchestratorOnly=true",
|
||||
),
|
||||
).toHaveLength(1);
|
||||
|
||||
|
|
@ -182,13 +182,16 @@ describe("SessionPage project polling", () => {
|
|||
vi
|
||||
.mocked(fetch)
|
||||
.mock.calls.filter(
|
||||
([url]) => url === "/api/sessions?project=my-app&orchestratorOnly=true&fresh=true",
|
||||
([url]) => url === "/api/sessions?project=my-app&orchestratorOnly=true",
|
||||
),
|
||||
).toHaveLength(1);
|
||||
|
||||
expect(
|
||||
vi.mocked(fetch).mock.calls.filter(([url]) => url === "/api/sessions?fresh=true"),
|
||||
vi.mocked(fetch).mock.calls.filter(([url]) => url === "/api/sessions"),
|
||||
).toHaveLength(3);
|
||||
expect(
|
||||
vi.mocked(fetch).mock.calls.filter(([url]) => String(url).includes("fresh=true")),
|
||||
).toHaveLength(0);
|
||||
});
|
||||
|
||||
it("does not deadlock project polling after a cached worker poll is skipped", async () => {
|
||||
|
|
@ -219,7 +222,7 @@ describe("SessionPage project polling", () => {
|
|||
} as Response;
|
||||
}
|
||||
|
||||
if (url === "/api/sessions?fresh=true") {
|
||||
if (url === "/api/sessions") {
|
||||
return {
|
||||
ok: true,
|
||||
status: 200,
|
||||
|
|
@ -227,7 +230,7 @@ describe("SessionPage project polling", () => {
|
|||
} as Response;
|
||||
}
|
||||
|
||||
if (url === "/api/sessions?project=my-app&orchestratorOnly=true&fresh=true") {
|
||||
if (url === "/api/sessions?project=my-app&orchestratorOnly=true") {
|
||||
return {
|
||||
ok: true,
|
||||
status: 200,
|
||||
|
|
@ -235,7 +238,7 @@ describe("SessionPage project polling", () => {
|
|||
} as Response;
|
||||
}
|
||||
|
||||
if (url === "/api/sessions?project=my-app&fresh=true") {
|
||||
if (url === "/api/sessions?project=my-app") {
|
||||
return {
|
||||
ok: true,
|
||||
status: 200,
|
||||
|
|
@ -257,7 +260,7 @@ describe("SessionPage project polling", () => {
|
|||
await flushAsyncWork();
|
||||
|
||||
expect(fetch).toHaveBeenCalledWith(
|
||||
"/api/sessions?project=my-app&fresh=true",
|
||||
"/api/sessions?project=my-app",
|
||||
expect.any(Object),
|
||||
);
|
||||
});
|
||||
|
|
@ -355,7 +358,7 @@ describe("SessionPage project polling", () => {
|
|||
});
|
||||
}
|
||||
|
||||
if (url === "/api/sessions?fresh=true") {
|
||||
if (url === "/api/sessions") {
|
||||
return Promise.resolve({
|
||||
ok: true,
|
||||
status: 200,
|
||||
|
|
@ -418,7 +421,7 @@ describe("SessionPage project polling", () => {
|
|||
return Promise.reject(new DOMException("Aborted", "AbortError"));
|
||||
}
|
||||
|
||||
if (url === "/api/sessions?fresh=true") {
|
||||
if (url === "/api/sessions") {
|
||||
return Promise.resolve({
|
||||
ok: true,
|
||||
status: 200,
|
||||
|
|
@ -477,7 +480,7 @@ describe("SessionPage project polling", () => {
|
|||
} as Response;
|
||||
}
|
||||
|
||||
if (url === "/api/sessions?fresh=true") {
|
||||
if (url === "/api/sessions") {
|
||||
return {
|
||||
ok: true,
|
||||
status: 200,
|
||||
|
|
@ -485,7 +488,7 @@ describe("SessionPage project polling", () => {
|
|||
} as Response;
|
||||
}
|
||||
|
||||
if (url === "/api/sessions?project=my-app&orchestratorOnly=true&fresh=true") {
|
||||
if (url === "/api/sessions?project=my-app&orchestratorOnly=true") {
|
||||
return {
|
||||
ok: true,
|
||||
status: 200,
|
||||
|
|
@ -507,7 +510,7 @@ describe("SessionPage project polling", () => {
|
|||
await flushAsyncWork();
|
||||
|
||||
expect(fetchMock.mock.calls.filter(([url]) => url === "/api/projects")).toHaveLength(2);
|
||||
expect(fetchMock.mock.calls.filter(([url]) => url === "/api/sessions?fresh=true")).toHaveLength(
|
||||
expect(fetchMock.mock.calls.filter(([url]) => url === "/api/sessions")).toHaveLength(
|
||||
2,
|
||||
);
|
||||
});
|
||||
|
|
@ -536,7 +539,7 @@ describe("SessionPage project polling", () => {
|
|||
} as Response);
|
||||
}
|
||||
|
||||
if (url === "/api/sessions?project=my-app&orchestratorOnly=true&fresh=true") {
|
||||
if (url === "/api/sessions?project=my-app&orchestratorOnly=true") {
|
||||
return Promise.resolve({
|
||||
ok: true,
|
||||
status: 200,
|
||||
|
|
@ -544,7 +547,7 @@ describe("SessionPage project polling", () => {
|
|||
} as Response);
|
||||
}
|
||||
|
||||
if (url === "/api/sessions?fresh=true") {
|
||||
if (url === "/api/sessions") {
|
||||
return new Promise<Response>((_, reject) => {
|
||||
init?.signal?.addEventListener(
|
||||
"abort",
|
||||
|
|
@ -597,7 +600,7 @@ describe("SessionPage project polling", () => {
|
|||
} as Response;
|
||||
}
|
||||
|
||||
if (url === "/api/sessions?fresh=true") {
|
||||
if (url === "/api/sessions") {
|
||||
return {
|
||||
ok: true,
|
||||
status: 200,
|
||||
|
|
@ -605,7 +608,7 @@ describe("SessionPage project polling", () => {
|
|||
} as Response;
|
||||
}
|
||||
|
||||
if (url === "/api/sessions?project=my-app&orchestratorOnly=true&fresh=true") {
|
||||
if (url === "/api/sessions?project=my-app&orchestratorOnly=true") {
|
||||
return {
|
||||
ok: true,
|
||||
status: 200,
|
||||
|
|
@ -649,7 +652,7 @@ describe("SessionPage project polling", () => {
|
|||
} as Response;
|
||||
}
|
||||
|
||||
if (url === "/api/sessions?fresh=true") {
|
||||
if (url === "/api/sessions") {
|
||||
return {
|
||||
ok: true,
|
||||
status: 200,
|
||||
|
|
@ -657,7 +660,7 @@ describe("SessionPage project polling", () => {
|
|||
} as Response;
|
||||
}
|
||||
|
||||
if (url === "/api/sessions?project=broken-app&orchestratorOnly=true&fresh=true") {
|
||||
if (url === "/api/sessions?project=broken-app&orchestratorOnly=true") {
|
||||
return {
|
||||
ok: true,
|
||||
status: 200,
|
||||
|
|
@ -704,7 +707,7 @@ describe("SessionPage project polling", () => {
|
|||
} as Response;
|
||||
}
|
||||
|
||||
if (url === "/api/sessions?fresh=true") {
|
||||
if (url === "/api/sessions") {
|
||||
return {
|
||||
ok: true,
|
||||
status: 200,
|
||||
|
|
@ -712,7 +715,7 @@ describe("SessionPage project polling", () => {
|
|||
} as Response;
|
||||
}
|
||||
|
||||
if (url === "/api/sessions?project=other-app&orchestratorOnly=true&fresh=true") {
|
||||
if (url === "/api/sessions?project=other-app&orchestratorOnly=true") {
|
||||
return {
|
||||
ok: true,
|
||||
status: 200,
|
||||
|
|
|
|||
|
|
@ -616,9 +616,13 @@ export default function SessionPage() {
|
|||
const controller = new AbortController();
|
||||
projectSessionsFetchControllerRef.current = controller;
|
||||
try {
|
||||
// Use the cached list path here. The session-detail sidebar refreshes on
|
||||
// mount and every poll tick; forcing `fresh=true` from this page defeats
|
||||
// sessionManager.listCached() and fans out tmux/ps probes while the page's
|
||||
// own session request is trying to load.
|
||||
const query = isOrchestrator
|
||||
? `/api/sessions?project=${encodeURIComponent(projectId)}&fresh=true`
|
||||
: `/api/sessions?project=${encodeURIComponent(projectId)}&orchestratorOnly=true&fresh=true`;
|
||||
? `/api/sessions?project=${encodeURIComponent(projectId)}`
|
||||
: `/api/sessions?project=${encodeURIComponent(projectId)}&orchestratorOnly=true`;
|
||||
const body = await fetchJsonWithTimeout<ProjectSessionsBody>(query, {
|
||||
signal: controller.signal,
|
||||
timeoutMs: PROJECT_SIDEBAR_FETCH_TIMEOUT_MS,
|
||||
|
|
@ -676,10 +680,13 @@ export default function SessionPage() {
|
|||
const controller = new AbortController();
|
||||
sidebarFetchControllerRef.current = controller;
|
||||
try {
|
||||
// This poll runs frequently and is fed by mux patches for freshness; do
|
||||
// not force the uncached `fresh=true` list path from the session-detail
|
||||
// page while the critical `/api/sessions/:id` request is loading.
|
||||
const body = await fetchJsonWithTimeout<{
|
||||
sessions?: DashboardSession[];
|
||||
orchestrators?: DashboardOrchestratorLink[];
|
||||
} | null>("/api/sessions?fresh=true", {
|
||||
} | null>("/api/sessions", {
|
||||
signal: controller.signal,
|
||||
timeoutMs: PROJECT_SIDEBAR_FETCH_TIMEOUT_MS,
|
||||
timeoutMessage: `Sidebar sessions request timed out after ${PROJECT_SIDEBAR_FETCH_TIMEOUT_MS}ms`,
|
||||
|
|
|
|||
Loading…
Reference in New Issue