perf: improve monitor query performance
This commit is contained in:
parent
89fed4666d
commit
f5c13cb02f
@ -1,7 +1,13 @@
|
|||||||
import { createTRPCReact, getQueryKey } from '@trpc/react-query';
|
import { createTRPCReact, getQueryKey } from '@trpc/react-query';
|
||||||
import type { inferRouterInputs, inferRouterOutputs } from '../../server/trpc';
|
import type { inferRouterInputs, inferRouterOutputs } from '../../server/trpc';
|
||||||
import type { AppRouter } from '../../server/trpc/routers';
|
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 { getJWT } from './auth';
|
||||||
import { message } from 'antd';
|
import { message } from 'antd';
|
||||||
import { isDev } from '../utils/env';
|
import { isDev } from '../utils/env';
|
||||||
@ -13,6 +19,14 @@ export const trpc = createTRPCReact<AppRouter>();
|
|||||||
export type AppRouterInput = inferRouterInputs<AppRouter>;
|
export type AppRouterInput = inferRouterInputs<AppRouter>;
|
||||||
export type AppRouterOutput = inferRouterOutputs<AppRouter>;
|
export type AppRouterOutput = inferRouterOutputs<AppRouter>;
|
||||||
|
|
||||||
|
const url = '/trpc';
|
||||||
|
|
||||||
|
function headers() {
|
||||||
|
return {
|
||||||
|
Authorization: `Bearer ${getJWT()}`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export const trpcClient = trpc.createClient({
|
export const trpcClient = trpc.createClient({
|
||||||
links: [
|
links: [
|
||||||
loggerLink({
|
loggerLink({
|
||||||
@ -20,13 +34,20 @@ export const trpcClient = trpc.createClient({
|
|||||||
(isDev && typeof window !== 'undefined') ||
|
(isDev && typeof window !== 'undefined') ||
|
||||||
(opts.direction === 'down' && opts.result instanceof Error),
|
(opts.direction === 'down' && opts.result instanceof Error),
|
||||||
}),
|
}),
|
||||||
httpBatchLink({
|
splitLink({
|
||||||
url: '/trpc',
|
condition(op) {
|
||||||
async headers() {
|
// check for context property `skipBatch`
|
||||||
return {
|
return op.context.skipBatch === true;
|
||||||
Authorization: `Bearer ${getJWT()}`,
|
|
||||||
};
|
|
||||||
},
|
},
|
||||||
|
true: httpLink({
|
||||||
|
url,
|
||||||
|
headers,
|
||||||
|
}),
|
||||||
|
// when condition is false, use batching
|
||||||
|
false: httpBatchLink({
|
||||||
|
url,
|
||||||
|
headers,
|
||||||
|
}),
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
@ -15,10 +15,19 @@ export const MonitorDataMetrics: React.FC<{
|
|||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const workspaceId = useCurrentWorkspaceId();
|
const workspaceId = useCurrentWorkspaceId();
|
||||||
const { monitorId, monitorType, currectResponse } = props;
|
const { monitorId, monitorType, currectResponse } = props;
|
||||||
const { data, isLoading } = trpc.monitor.dataMetrics.useQuery({
|
const { data, isLoading } = trpc.monitor.dataMetrics.useQuery(
|
||||||
workspaceId,
|
{
|
||||||
monitorId,
|
workspaceId,
|
||||||
});
|
monitorId,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
trpc: {
|
||||||
|
context: {
|
||||||
|
skipBatch: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
const provider = useMemo(
|
const provider = useMemo(
|
||||||
() => getMonitorProvider(monitorType),
|
() => getMonitorProvider(monitorType),
|
||||||
|
@ -70,6 +70,9 @@ export const MonitorInfo: React.FC<MonitorInfoProps> = React.memo((props) => {
|
|||||||
active: true,
|
active: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
trpcUtils.monitor.all.refetch({
|
||||||
|
workspaceId,
|
||||||
|
});
|
||||||
trpcUtils.monitor.get.refetch({
|
trpcUtils.monitor.get.refetch({
|
||||||
workspaceId,
|
workspaceId,
|
||||||
monitorId,
|
monitorId,
|
||||||
@ -87,6 +90,9 @@ export const MonitorInfo: React.FC<MonitorInfoProps> = React.memo((props) => {
|
|||||||
active: false,
|
active: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
trpcUtils.monitor.all.refetch({
|
||||||
|
workspaceId,
|
||||||
|
});
|
||||||
trpcUtils.monitor.get.refetch({
|
trpcUtils.monitor.get.refetch({
|
||||||
workspaceId,
|
workspaceId,
|
||||||
monitorId,
|
monitorId,
|
||||||
|
@ -139,7 +139,7 @@ export const ServerList: React.FC<ServerListProps> = React.memo((props) => {
|
|||||||
cell: (props) => dayjs(props.getValue()).format('MMM D HH:mm:ss'),
|
cell: (props) => dayjs(props.getValue()).format('MMM D HH:mm:ss'),
|
||||||
}),
|
}),
|
||||||
];
|
];
|
||||||
}, []);
|
}, [t]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex h-full flex-col">
|
<div className="flex h-full flex-col">
|
||||||
|
@ -10,7 +10,6 @@ import {
|
|||||||
AlertDialogTrigger,
|
AlertDialogTrigger,
|
||||||
} from '@/components/ui/alert-dialog';
|
} from '@/components/ui/alert-dialog';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { ScrollArea } from '@/components/ui/scroll-area';
|
|
||||||
import { Separator } from '@/components/ui/separator';
|
import { Separator } from '@/components/ui/separator';
|
||||||
import { Switch } from '@/components/ui/switch';
|
import { Switch } from '@/components/ui/switch';
|
||||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
||||||
|
53
src/server/model/monitor/index.bench.ts
Normal file
53
src/server/model/monitor/index.bench.ts
Normal 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());
|
||||||
|
});
|
||||||
|
});
|
@ -48,17 +48,22 @@ export function getMonitorRecentData(
|
|||||||
monitorId: string,
|
monitorId: string,
|
||||||
take: number
|
take: number
|
||||||
) {
|
) {
|
||||||
return prisma.monitorData.findMany({
|
return prisma.monitorData
|
||||||
where: {
|
.findMany({
|
||||||
monitor: {
|
where: {
|
||||||
id: monitorId,
|
monitor: {
|
||||||
workspaceId,
|
id: monitorId,
|
||||||
|
workspaceId,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
take,
|
||||||
take: -take,
|
orderBy: {
|
||||||
select: {
|
createdAt: 'desc',
|
||||||
value: true,
|
},
|
||||||
createdAt: true,
|
select: {
|
||||||
},
|
value: true,
|
||||||
});
|
createdAt: true,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.then((arr) => arr.reverse());
|
||||||
}
|
}
|
||||||
|
@ -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");
|
@ -318,6 +318,8 @@ model MonitorEvent {
|
|||||||
createdAt DateTime @default(now()) @db.Timestamptz(6)
|
createdAt DateTime @default(now()) @db.Timestamptz(6)
|
||||||
|
|
||||||
monitor Monitor @relation(fields: [monitorId], references: [id], onUpdate: Cascade, onDelete: Cascade)
|
monitor Monitor @relation(fields: [monitorId], references: [id], onUpdate: Cascade, onDelete: Cascade)
|
||||||
|
|
||||||
|
@@index([monitorId])
|
||||||
}
|
}
|
||||||
|
|
||||||
model MonitorData {
|
model MonitorData {
|
||||||
@ -329,6 +331,8 @@ model MonitorData {
|
|||||||
monitor Monitor @relation(fields: [monitorId], references: [id], onUpdate: Cascade, onDelete: Cascade)
|
monitor Monitor @relation(fields: [monitorId], references: [id], onUpdate: Cascade, onDelete: Cascade)
|
||||||
|
|
||||||
@@index([createdAt])
|
@@index([createdAt])
|
||||||
|
@@index([monitorId, createdAt(sort: Desc)])
|
||||||
|
@@index([monitorId, createdAt, value])
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use for record latest monitor status, for example tls status
|
// Use for record latest monitor status, for example tls status
|
||||||
|
@ -300,14 +300,13 @@ export const monitorRouter = router({
|
|||||||
return monitor;
|
return monitor;
|
||||||
}),
|
}),
|
||||||
recentData: publicProcedure
|
recentData: publicProcedure
|
||||||
.meta({
|
.meta(
|
||||||
openapi: {
|
buildMonitorOpenapi({
|
||||||
tags: [OPENAPI_TAG.MONITOR],
|
|
||||||
protect: false,
|
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
path: `/monitor/{monitorId}/recentData`,
|
protect: false,
|
||||||
},
|
path: '/{monitorId}/recentData',
|
||||||
})
|
})
|
||||||
|
)
|
||||||
.input(
|
.input(
|
||||||
z.object({
|
z.object({
|
||||||
workspaceId: z.string().cuid2(),
|
workspaceId: z.string().cuid2(),
|
||||||
|
Loading…
Reference in New Issue
Block a user