-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathclient.ts
More file actions
71 lines (58 loc) · 2.58 KB
/
Copy pathclient.ts
File metadata and controls
71 lines (58 loc) · 2.58 KB
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
import { createORPCClient } from "@orpc/client";
import { RPCLink } from "@orpc/client/websocket";
import type { RouterClient } from "@orpc/server";
import type { router } from "../src/main.ts";
const URL = `ws://127.0.0.1:${process.env.PORT ?? "3000"}`;
const CONNECTIONS = 10;
const DURATION_MS = 20_000;
function createClient(): RouterClient<typeof router> {
const link = new RPCLink({
connect: () => new WebSocket(URL),
connectOnInit: true,
});
return createORPCClient(link);
}
function percentile(sorted: number[], p: number): number {
return sorted[Math.min(sorted.length - 1, Math.floor((p / 100) * sorted.length))] ?? 0;
}
function printSummary(latencies: number[], perSecond: number[], elapsedSeconds: number): void {
const sorted = [...latencies].sort((a, b) => a - b);
const total = latencies.length;
const avg = latencies.reduce((a, b) => a + b, 0) / total;
const stdev = Math.sqrt(latencies.reduce((a, b) => a + (b - avg) ** 2, 0) / total);
const rpsAvg = perSecond.reduce((a, b) => a + b, 0) / perSecond.length;
const rpsStdev = Math.sqrt(
perSecond.reduce((a, b) => a + (b - rpsAvg) ** 2, 0) / perSecond.length,
);
const ms = (value: number) => `${value.toFixed(2)} ms`;
const int = (value: number) => Math.round(value).toLocaleString("en-US");
// eslint-disable-next-line no-console
console.log(
[
`Latency: avg=${ms(avg)} stdev=${ms(stdev)} p50=${ms(percentile(sorted, 50))} p97.5=${ms(percentile(sorted, 97.5))} p99=${ms(percentile(sorted, 99))} max=${ms(sorted[sorted.length - 1] ?? 0)}`,
`Req/Sec: avg=${int(rpsAvg)} stdev=${int(rpsStdev)} min=${int(Math.min(...perSecond))} max=${int(Math.max(...perSecond))}`,
"",
`${int(total)} requests in ${elapsedSeconds.toFixed(2)}s`,
].join("\n"),
);
}
const clients = Array.from({ length: CONNECTIONS }, () => createClient());
const latencies: number[] = [];
const perSecond = new Array(Math.ceil(DURATION_MS / 1000)).fill(0);
// eslint-disable-next-line no-console
console.log(`Running ${DURATION_MS / 1000}s WebSocket test @ ${URL}\n${CONNECTIONS} connections\n`);
const start = performance.now();
const end = start + DURATION_MS;
await Promise.all(
clients.map(async (client) => {
while (performance.now() < end) {
const began = performance.now();
await client.nested.procedure_1("hello world");
const finished = performance.now();
latencies.push(finished - began);
perSecond[Math.min(perSecond.length - 1, Math.floor((finished - start) / 1000))]++;
}
}),
);
printSummary(latencies, perSecond, (performance.now() - start) / 1000);
process.exit(0);