perf: improve monitor query performance

This commit is contained in:
moonrailgun 2024-04-24 00:33:30 +08:00
parent 89fed4666d
commit f5c13cb02f
10 changed files with 136 additions and 32 deletions

View File

@ -1,7 +1,13 @@
import { createTRPCReact, getQueryKey } from '@trpc/react-query';
import type { inferRouterInputs, inferRouterOutputs } from '../../server/trpc';
import type { AppRouter } from '../../server/trpc/routers';
import { httpBatchLink, loggerLink, TRPCClientErrorLike } from '@trpc/client';
import {
httpBatchLink,
httpLink,
loggerLink,
splitLink,
TRPCClientErrorLike,
} from '@trpc/client';
import { getJWT } from './auth';
import { message } from 'antd';
import { isDev } from '../utils/env';
@ -13,6 +19,14 @@ export const trpc = createTRPCReact<AppRouter>();
export type AppRouterInput = inferRouterInputs<AppRouter>;
export type AppRouterOutput = inferRouterOutputs<AppRouter>;
const url = '/trpc';
function headers() {
return {
Authorization: `Bearer ${getJWT()}`,
};
}
export const trpcClient = trpc.createClient({
links: [
loggerLink({
@ -20,13 +34,20 @@ export const trpcClient = trpc.createClient({
(isDev && typeof window !== 'undefined') ||
(opts.direction === 'down' && opts.result instanceof Error),
}),
httpBatchLink({
url: '/trpc',
async headers() {
return {
Authorization: `Bearer ${getJWT()}`,
};
splitLink({
condition(op) {
// check for context property `skipBatch`
return op.context.skipBatch === true;
},
true: httpLink({
url,
headers,
}),
// when condition is false, use batching
false: httpBatchLink({
url,
headers,
}),
}),
],
});

View File

@ -15,10 +15,19 @@ export const MonitorDataMetrics: React.FC<{
const { t } = useTranslation();
const workspaceId = useCurrentWorkspaceId();
const { monitorId, monitorType, currectResponse } = props;
const { data, isLoading } = trpc.monitor.dataMetrics.useQuery({
const { data, isLoading } = trpc.monitor.dataMetrics.useQuery(
{
workspaceId,
monitorId,
});
},
{
trpc: {
context: {
skipBatch: true,
},
},
}
);
const provider = useMemo(
() => getMonitorProvider(monitorType),

View File

@ -70,6 +70,9 @@ export const MonitorInfo: React.FC<MonitorInfoProps> = React.memo((props) => {
active: true,
});
trpcUtils.monitor.all.refetch({
workspaceId,
});
trpcUtils.monitor.get.refetch({
workspaceId,
monitorId,
@ -87,6 +90,9 @@ export const MonitorInfo: React.FC<MonitorInfoProps> = React.memo((props) => {
active: false,
});
trpcUtils.monitor.all.refetch({
workspaceId,
});
trpcUtils.monitor.get.refetch({
workspaceId,
monitorId,

View File

@ -139,7 +139,7 @@ export const ServerList: React.FC<ServerListProps> = React.memo((props) => {
cell: (props) => dayjs(props.getValue()).format('MMM D HH:mm:ss'),
}),
];
}, []);
}, [t]);
return (
<div className="flex h-full flex-col">

View File

@ -10,7 +10,6 @@ import {
AlertDialogTrigger,
} from '@/components/ui/alert-dialog';
import { Button } from '@/components/ui/button';
import { ScrollArea } from '@/components/ui/scroll-area';
import { Separator } from '@/components/ui/separator';
import { Switch } from '@/components/ui/switch';
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';

View File

@ -0,0 +1,53 @@
import { describe, bench } from 'vitest';
import { prisma } from '../_client';
const workspaceId = process.env.BENCH_MONITOR_WORKSPACEID;
const monitorId = process.env.BENCH_MONITOR_ID;
describe.runIf(workspaceId && monitorId)('getMonitorRecentData', () => {
bench('find with join', async () => {
await prisma.monitorData
.findMany({
where: {
monitor: {
id: monitorId,
workspaceId,
},
},
take: 20,
orderBy: {
createdAt: 'desc',
},
select: {
value: true,
createdAt: true,
},
})
.then((arr) => arr.reverse());
});
bench('find with double check', async () => {
await prisma.monitor.findFirstOrThrow({
where: {
workspaceId,
id: monitorId,
},
});
await prisma.monitorData
.findMany({
where: {
monitorId,
},
take: 20,
orderBy: {
createdAt: 'desc',
},
select: {
value: true,
createdAt: true,
},
})
.then((arr) => arr.reverse());
});
});

View File

@ -48,17 +48,22 @@ export function getMonitorRecentData(
monitorId: string,
take: number
) {
return prisma.monitorData.findMany({
return prisma.monitorData
.findMany({
where: {
monitor: {
id: monitorId,
workspaceId,
},
},
take: -take,
take,
orderBy: {
createdAt: 'desc',
},
select: {
value: true,
createdAt: true,
},
});
})
.then((arr) => arr.reverse());
}

View File

@ -0,0 +1,8 @@
-- CreateIndex
CREATE INDEX "MonitorData_monitorId_createdAt_idx" ON "MonitorData"("monitorId", "createdAt" DESC);
-- CreateIndex
CREATE INDEX "MonitorData_monitorId_createdAt_value_idx" ON "MonitorData"("monitorId", "createdAt", "value");
-- CreateIndex
CREATE INDEX "MonitorEvent_monitorId_idx" ON "MonitorEvent"("monitorId");

View File

@ -318,6 +318,8 @@ model MonitorEvent {
createdAt DateTime @default(now()) @db.Timestamptz(6)
monitor Monitor @relation(fields: [monitorId], references: [id], onUpdate: Cascade, onDelete: Cascade)
@@index([monitorId])
}
model MonitorData {
@ -329,6 +331,8 @@ model MonitorData {
monitor Monitor @relation(fields: [monitorId], references: [id], onUpdate: Cascade, onDelete: Cascade)
@@index([createdAt])
@@index([monitorId, createdAt(sort: Desc)])
@@index([monitorId, createdAt, value])
}
// Use for record latest monitor status, for example tls status

View File

@ -300,14 +300,13 @@ export const monitorRouter = router({
return monitor;
}),
recentData: publicProcedure
.meta({
openapi: {
tags: [OPENAPI_TAG.MONITOR],
protect: false,
.meta(
buildMonitorOpenapi({
method: 'GET',
path: `/monitor/{monitorId}/recentData`,
},
protect: false,
path: '/{monitorId}/recentData',
})
)
.input(
z.object({
workspaceId: z.string().cuid2(),