Skip to content
Source
Sign inSign up

SlowRpcRequestToastCoordinator.tsx

67 lines2.1 KB

1import { type SlowRpcAckRequest, subscribeSlowRpcAckRequests } from "../rpc/requestLatencyState";
2import { toastManager } from "./ui/toast";
3​
4function describeSlowRequests(requests: ReadonlyArray<SlowRpcAckRequest>): string {
5 const count = requests.length;
6 const thresholdSeconds = Math.round(
7 Math.min(...requests.map((request) => request.thresholdMs)) / 1000,
8 );
9​
10 return `${count} request${count === 1 ? "" : "s"} waiting longer than ${thresholdSeconds}s.`;
12​
13function SlowRequestDetails({ requests }: { requests: ReadonlyArray<SlowRpcAckRequest> }) {
14 return (
15 <ul className="space-y-2.5 text-xs text-muted-foreground">
16 {requests.map((request) => (
17 <li
18 className="min-w-0 border-border/50 border-b pb-2 last:border-b-0 last:pb-0"
19 key={request.requestId}
20 >
21 <div className="wrap-break-word font-medium text-foreground">{request.tag}</div>
22 <div className="mt-0.5 text-3xs opacity-75">
23 Started {new Date(request.startedAt).toLocaleTimeString()}
24 </div>
25 </li>
26 ))}
27 </ul>
28 );
30​
31/** One warning toast that tracks the set of slow requests while any are outstanding. */
32export function startSlowRpcRequestToasts(): () => void {
33 let toastId: ReturnType<typeof toastManager.add> | null = null;
34​
35 const unsubscribe = subscribeSlowRpcAckRequests((slowRequests) => {
36 if (slowRequests.length === 0) {
37 if (toastId !== null) {
38 toastManager.close(toastId);
39 toastId = null;
40 }
41 return;
42 }
43​
44 const nextToast = {
45 data: {
46 expandableContent: <SlowRequestDetails requests={slowRequests} />,
47 expandableDescriptionTrigger: true,
48 expandableLabels: { collapse: "Hide requests", expand: "Show requests" },
49 },
50 description: describeSlowRequests(slowRequests),
51 timeout: 0,
52 title: "Some requests are slow",
53 type: "warning" as const,
54 };
55​
56 if (toastId === null) {
57 toastId = toastManager.add(nextToast);
58 } else {
59 toastManager.update(toastId, nextToast);
60 }
61 });
62​
63 return () => {
64 unsubscribe();
65 if (toastId !== null) toastManager.close(toastId);
66 };