~james/core

core/web/src/lib/ssr/pool.test.ts -rw-r--r-- 4.2 KiB
452f17b7 — james chore(import): snapshot james.dad.town/core at f70c71c7696a 15 hours ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
import { getHeapStatistics } from "node:v8";
import { describe, expect, it, vi } from "vitest";
import { render } from "#lib/ssr/pool.ts";
import { RENDER_QUEUE_WAIT_MS, type RenderTask } from "#lib/ssr/render.ts";

vi.mock(import("node:v8"), async (original) => ({
	...(await original()),
	getHeapStatistics: vi.fn((await original()).getHeapStatistics)
}));

const ctx = { repo: "ada.test/infra", ref: "main" };
const markup = (source: string) => (): RenderTask => ({ kind: "markup", source, ctx });

describe("render pool", () => {
	const slow = (tag: string) =>
		markup(
			Array.from(
				{ length: 400 },
				(_, i) => `## ${tag}${i}\n\n\`\`\`ts\nconst x${i} = ${i};\n\`\`\``
			).join("\n\n")
		)();

	let warmups = 0;
	const idleWorker = () => render(markup(`warm-up ${warmups++}`)(), 10_000);

	it("drops a render past its timeout and keeps rendering after", async () => {
		await idleWorker();
		expect(await render(slow("timeout"), 1)).toBeNull();
		expect(await render(markup("**ok**")(), 10_000)).toContain("<strong>ok</strong>");
	});

	it("drops a render that's no longer wanted once a worker is free", async () => {
		expect(await render(markup("**unwanted**")(), 10_000, {}, () => false)).toBeNull();
	});

	it("serves a document rendered before without rendering it again", async () => {
		const task = slow("cached");
		const html = await render(task, 10_000);
		expect(html).toContain("cached399");
		expect(await render(task, 1)).toBe(html);
	});

	it("stops caching while the heap is near its limit", async () => {
		vi.useFakeTimers({ toFake: ["Date"], now: Date.now() + 60_000 });
		const real = getHeapStatistics();
		vi.mocked(getHeapStatistics).mockReturnValue({
			...real,
			used_heap_size: real.heap_size_limit
		});
		const task = slow("pressure");
		expect(await render(task, 10_000)).toContain("pressure399");
		vi.mocked(getHeapStatistics).mockRestore();
		vi.setSystemTime(Date.now() + 60_000);
		await idleWorker();
		vi.useRealTimers();
		expect(await render(task, 1)).toBeNull();
	});

	it("remembers a document whose render timed out instead of retrying it each time", async () => {
		const task = slow("hangs");
		await idleWorker();
		expect(await render(task, 50)).toBeNull();
		expect(await render(task, 10_000)).toBeNull();
	});

	// node < 26 aborts the whole process when a worker ooms inside a builtin call
	it.skipIf(Number(process.versions.node.split(".")[0]) < 26)(
		"survives a render that takes its worker down, and keeps rendering after",
		async () => {
			const huge = markup("a\n\n".repeat(4_000_000))();
			expect(await render(huge, 60_000)).toBeNull();
			expect(await render(markup("**after the crash**")(), 10_000)).toContain(
				"<strong>after the crash</strong>"
			);
		}
	);

	it("doesn't hold a timeout spent waiting for a worker against the document", async () => {
		await idleWorker();
		const busy = Array.from({ length: 16 }, (_, i) => render(slow(`queue${i}-`), 60_000));
		const task = markup("**waited too long**")();
		expect(await render(task, 30, {})).toBeNull();
		expect(await render(task, 60_000)).toContain("<strong>waited too long</strong>");
		await Promise.all(busy);
	});

	it("gives up on a render no worker takes in time, however long its timeout", async () => {
		await idleWorker();
		const busy = Array.from({ length: 200 }, (_, i) => render(slow(`lane${i}-`), 60_000, {}));
		const asked = Date.now();
		expect(await render(markup("**late**")(), 60_000, {})).toBeNull();
		expect(Date.now() - asked).toBeLessThan(RENDER_QUEUE_WAIT_MS * 2);
		await Promise.all(busy);
	});

	it("renders a document asked for twice at once only once", async () => {
		await idleWorker();
		const task = slow("twice");
		const first = render(task, 10_000);
		const second = render(task, 1);
		const [a, b] = await Promise.all([first, second]);
		expect(a).toContain("twice399");
		expect(b).toBe(a);
	});

	it("takes turns between owners instead of serving the queue in order", async () => {
		const busy = {};
		let busyDone = 0;
		const queued = Array.from({ length: 40 }, (_, i) =>
			render(slow(`busy${i}-`), 60_000, busy).then(() => busyDone++)
		);
		await render(markup("**other page**")(), 60_000, {});
		expect(busyDone).toBeLessThan(20);
		await Promise.all(queued);
	});
});