perf(web): queue dashboard tile hydration
This commit is contained in:
parent
83c2c0f4a4
commit
fd0559a143
4 changed files with 194 additions and 6 deletions
|
|
@ -1,7 +1,9 @@
|
|||
import { describe, expect, test } from "vitest";
|
||||
import {
|
||||
attachDashboardRefreshLifecycle,
|
||||
createDashboardTileBackoff,
|
||||
createDashboardRequestAborter,
|
||||
runDashboardHydrationQueue,
|
||||
shouldPauseDashboardRefresh,
|
||||
} from "./dashboard-refresh";
|
||||
|
||||
|
|
@ -73,4 +75,69 @@ describe("dashboard refresh lifecycle", () => {
|
|||
|
||||
expect(calls).toEqual(["pause", "pause", "pause", "load", "load"]);
|
||||
});
|
||||
|
||||
test("limits tile hydration concurrency", async () => {
|
||||
let active = 0;
|
||||
let maxActive = 0;
|
||||
const started: number[] = [];
|
||||
const releases = new Map<number, () => void>();
|
||||
|
||||
const queue = runDashboardHydrationQueue({
|
||||
concurrency: 2,
|
||||
items: [1, 2, 3, 4],
|
||||
signal: new AbortController().signal,
|
||||
hydrate: async (item) => {
|
||||
active += 1;
|
||||
maxActive = Math.max(maxActive, active);
|
||||
started.push(item);
|
||||
await new Promise<void>((resolve) => releases.set(item, resolve));
|
||||
active -= 1;
|
||||
},
|
||||
});
|
||||
|
||||
await waitFor(() => started.length === 2);
|
||||
expect(started).toEqual([1, 2]);
|
||||
expect(maxActive).toBe(2);
|
||||
|
||||
releases.get(1)?.();
|
||||
await waitFor(() => started.length === 3);
|
||||
expect(started).toEqual([1, 2, 3]);
|
||||
expect(maxActive).toBe(2);
|
||||
|
||||
releases.get(2)?.();
|
||||
releases.get(3)?.();
|
||||
await waitFor(() => started.length === 4);
|
||||
releases.get(4)?.();
|
||||
await queue;
|
||||
expect(maxActive).toBe(2);
|
||||
});
|
||||
|
||||
test("backs off failed tile keys and resets after success", () => {
|
||||
const backoff = createDashboardTileBackoff();
|
||||
|
||||
backoff.recordFailure("telemetry:infra-ram", 1_000);
|
||||
expect(backoff.canAttempt("telemetry:infra-ram", 15_999)).toBe(false);
|
||||
expect(backoff.canAttempt("telemetry:infra-ram", 16_000)).toBe(true);
|
||||
|
||||
backoff.recordFailure("telemetry:infra-ram", 16_000);
|
||||
expect(backoff.canAttempt("telemetry:infra-ram", 45_999)).toBe(false);
|
||||
expect(backoff.canAttempt("telemetry:infra-ram", 46_000)).toBe(true);
|
||||
|
||||
backoff.recordFailure("telemetry:infra-ram", 46_000);
|
||||
backoff.recordFailure("telemetry:infra-ram", 106_000);
|
||||
expect(backoff.canAttempt("telemetry:infra-ram", 225_999)).toBe(false);
|
||||
expect(backoff.canAttempt("telemetry:infra-ram", 226_000)).toBe(true);
|
||||
|
||||
backoff.recordSuccess("telemetry:infra-ram");
|
||||
expect(backoff.canAttempt("telemetry:infra-ram", 107_000)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
async function waitFor(predicate: () => boolean) {
|
||||
for (let attempt = 0; attempt < 20; attempt += 1) {
|
||||
if (predicate()) return;
|
||||
await Promise.resolve();
|
||||
}
|
||||
|
||||
throw new Error("condition was not met");
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue