Skip to content

Commit a4b8e38

Browse files
authored
chore: add p50/p90 queue metrics to health check (#604)
* chore: add p50/p90 queue metrics to health check * get last 1k sent txs
1 parent f4dd34e commit a4b8e38

File tree

3 files changed

+85
-0
lines changed

3 files changed

+85
-0
lines changed

src/server/routes/system/queue.ts

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import { Static, Type } from "@sinclair/typebox";
22
import { FastifyInstance } from "fastify";
33
import { StatusCodes } from "http-status-codes";
4+
import { prisma } from "../../../db/client";
45
import { getQueueStatus } from "../../../db/transactions/getQueueStatus";
6+
import { getPercentile } from "../../../utils/math";
57
import { standardResponseSchema } from "../../schemas/sharedApiSchemas";
68

79
const QuerySchema = Type.Object({
@@ -12,6 +14,16 @@ const responseBodySchema = Type.Object({
1214
result: Type.Object({
1315
queued: Type.Number(),
1416
pending: Type.Number(),
17+
latency: Type.Object({
18+
msToSend: Type.Object({
19+
p50: Type.Number(),
20+
p90: Type.Number(),
21+
}),
22+
msToMine: Type.Object({
23+
p50: Type.Number(),
24+
p90: Type.Number(),
25+
}),
26+
}),
1527
}),
1628
});
1729

@@ -37,11 +49,46 @@ export async function queueStatus(fastify: FastifyInstance) {
3749
handler: async (req, res) => {
3850
const { walletAddress } = req.query;
3951

52+
// Get # queued and sent transactions.
4053
const { queued, pending } = await getQueueStatus({ walletAddress });
54+
55+
// Get last 1k sent transactions.
56+
const recentTransactions = await prisma.transactions.findMany({
57+
orderBy: { queuedAt: "desc" },
58+
where: { sentAt: { not: null } },
59+
take: 1_000,
60+
});
61+
62+
// Get "queue -> send" and "queue -> mine" times.
63+
const msToSendArr: number[] = [];
64+
const msToMineArr: number[] = [];
65+
for (const transaction of recentTransactions) {
66+
const queuedAt = transaction.queuedAt.getTime();
67+
const sentAt = transaction.sentAt?.getTime();
68+
const minedAt = transaction.minedAt?.getTime();
69+
70+
if (sentAt) {
71+
msToSendArr.push(sentAt - queuedAt);
72+
}
73+
if (minedAt) {
74+
msToMineArr.push(minedAt - queuedAt);
75+
}
76+
}
77+
4178
res.status(StatusCodes.OK).send({
4279
result: {
4380
queued,
4481
pending,
82+
latency: {
83+
msToSend: {
84+
p50: getPercentile(msToSendArr, 50),
85+
p90: getPercentile(msToSendArr, 90),
86+
},
87+
msToMine: {
88+
p50: getPercentile(msToMineArr, 50),
89+
p90: getPercentile(msToMineArr, 90),
90+
},
91+
},
4592
},
4693
});
4794
},

src/tests/math.test.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { describe, expect, it } from "vitest";
2+
import { getPercentile } from "../utils/math";
3+
4+
describe("getPercentile", () => {
5+
it("should correctly calculate the p50 (median) of a sorted array", () => {
6+
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
7+
expect(getPercentile(numbers, 50)).toBe(5);
8+
});
9+
10+
it("should correctly calculate the p90 of a sorted array", () => {
11+
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
12+
expect(getPercentile(numbers, 90)).toBe(9);
13+
});
14+
15+
it("should handle arrays with even number of elements", () => {
16+
const numbers = [10, 20, 30, 40, 50, 60, 70, 80];
17+
expect(getPercentile(numbers, 50)).toBe(40);
18+
});
19+
20+
it("should handle single element array", () => {
21+
const numbers = [1];
22+
expect(getPercentile(numbers, 50)).toBe(1);
23+
});
24+
25+
it("should handle empty array", () => {
26+
const numbers: number[] = [];
27+
expect(getPercentile(numbers, 50)).toBe(0);
28+
});
29+
});

src/utils/math.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
export const getPercentile = (arr: number[], percentile: number): number => {
2+
if (arr.length === 0) {
3+
return 0;
4+
}
5+
6+
arr.sort((a, b) => a - b);
7+
const index = Math.floor((percentile / 100) * (arr.length - 1));
8+
return arr[index];
9+
};

0 commit comments

Comments
 (0)