perf: New getTeamSchedule route with higher vCPUs (#17277)

This commit is contained in:
Keith Williams authored and GitHub committed 2024-10-23 13:38:15 -07:00
1 parent 123a39bd9a
commit b38d8e7ae4
9 files changed
+106 -41

No files matched your search

@@ -0,0 +1,4 @@
import { createNextApiHandler } from "@calcom/trpc/server/createNextApiHandler";
import { highPerfRouter } from "@calcom/trpc/server/routers/viewer/highPerf/_router";
export default createNextApiHandler(highPerfRouter);
+2 -5
View File
@@ -14,11 +14,8 @@
}
],
"functions": {
"pages/api/trpc/public/[trpc].ts": {
"memory": 1024
},
"pages/api/trpc/slots/[trpc].ts": {
"memory": 1024
"pages/api/trpc/highPerf/[trpc].ts": {
"memory": 3008
},
"pages/api/trpc/appRoutingForms/[trpc].ts": {
"memory": 2048
@@ -48,40 +48,46 @@ export const useSchedule = ({
const searchParams = useSearchParams();
const routedTeamMemberIds = searchParams ? getRoutedTeamMemberIdsFromSearchParams(searchParams) : null;
const skipContactOwner = searchParams ? searchParams.get("cal.skipContactOwner") === "true" : false;
return trpc.viewer.public.slots.getSchedule.useQuery(
{
isTeamEvent,
usernameList: getUsernameList(username ?? ""),
// Prioritize slug over id, since slug is the first value we get available.
// If we have a slug, we don't need to fetch the id.
// TODO: are queries using eventTypeId faster? Even tho we lost time fetching the id with the slug.
...(eventSlug ? { eventTypeSlug: eventSlug } : { eventTypeId: eventId ?? 0 }),
// @TODO: Old code fetched 2 days ago if we were fetching the current month.
// Do we want / need to keep that behavior?
startTime,
// if `prefetchNextMonth` is true, two months are fetched at once.
endTime,
timeZone: timezone!,
duration: duration ? `${duration}` : undefined,
rescheduleUid,
orgSlug,
teamMemberEmail,
routedTeamMemberIds,
skipContactOwner,
},
{
trpc: {
context: {
skipBatch: true,
},
const input = {
isTeamEvent,
usernameList: getUsernameList(username ?? ""),
// Prioritize slug over id, since slug is the first value we get available.
// If we have a slug, we don't need to fetch the id.
// TODO: are queries using eventTypeId faster? Even tho we lost time fetching the id with the slug.
...(eventSlug ? { eventTypeSlug: eventSlug } : { eventTypeId: eventId ?? 0 }),
// @TODO: Old code fetched 2 days ago if we were fetching the current month.
// Do we want / need to keep that behavior?
startTime,
// if `prefetchNextMonth` is true, two months are fetched at once.
endTime,
timeZone: timezone!,
duration: duration ? `${duration}` : undefined,
rescheduleUid,
orgSlug,
teamMemberEmail,
routedTeamMemberIds,
skipContactOwner,
};
const options = {
trpc: {
context: {
skipBatch: true,
},
refetchOnWindowFocus: false,
enabled:
Boolean(username) &&
Boolean(month) &&
Boolean(timezone) &&
// Should only wait for one or the other, not both.
(Boolean(eventSlug) || Boolean(eventId) || eventId === 0),
}
);
},
refetchOnWindowFocus: false,
enabled:
Boolean(username) &&
Boolean(month) &&
Boolean(timezone) &&
// Should only wait for one or the other, not both.
(Boolean(eventSlug) || Boolean(eventId) || eventId === 0),
};
if (isTeamEvent) {
return trpc.viewer.highPerf.getTeamSchedule.useQuery(input, options);
}
return trpc.viewer.public.slots.getSchedule.useQuery(input, options);
};
+1
View File
@@ -13,6 +13,7 @@ export const ENDPOINTS = [
"dsync",
"eventTypes",
"features",
"highPerf",
"insights",
"payments",
"public",
+2 -1
View File
@@ -71,7 +71,8 @@ export function createNextApiHandler(router: AnyRouter, isPublic = false, namesp
cityTimezones: SETTING_FOR_CACHED_BY_VERSION,
// FIXME: Using `max-age=1, stale-while-revalidate=60` fails some booking tests.
"slots.getSchedule": `no-cache`,
"slots.getSchedule": `no-cache`, // INFO: This needs the slots prefix because it lives us the public router
getTeamSchedule: `no-cache`,
// Feature Flags change but it might be okay to have a 5 minute cache to avoid burdening the servers with requests for this.
// Note that feature flags can be used to quickly kill a feature if it's not working as expected. So, we have to keep fresh time lesser than the deployment time atleast
@@ -19,6 +19,7 @@ import { deploymentSetupRouter } from "./deploymentSetup/_router";
import { dsyncRouter } from "./dsync/_router";
import { eventTypesRouter } from "./eventTypes/_router";
import { googleWorkspaceRouter } from "./googleWorkspace/_router";
import { highPerfRouter } from "./highPerf/_router";
import { oAuthRouter } from "./oAuth/_router";
import { viewerOrganizationsRouter } from "./organizations/_router";
import { paymentsRouter } from "./payments/_router";
@@ -61,5 +62,6 @@ export const viewerRouter = mergeRouters(
googleWorkspace: googleWorkspaceRouter,
admin: adminRouter,
attributes: attributesRouter,
highPerf: highPerfRouter,
})
);
@@ -0,0 +1,30 @@
import publicProcedure from "../../../procedures/publicProcedure";
import { router } from "../../../trpc";
import { ZGetTeamScheduleInputSchema } from "./getTeamSchedule.schema";
type SlotsRouterHandlerCache = {
getTeamSchedule?: typeof import("./getTeamSchedule.handler").getTeamScheduleHandler;
};
const UNSTABLE_HANDLER_CACHE: SlotsRouterHandlerCache = {};
/** This should be called getAvailableSlots */
export const highPerfRouter = router({
getTeamSchedule: publicProcedure.input(ZGetTeamScheduleInputSchema).query(async ({ input, ctx }) => {
if (!UNSTABLE_HANDLER_CACHE.getTeamSchedule) {
UNSTABLE_HANDLER_CACHE.getTeamSchedule = await import("./getTeamSchedule.handler").then(
(mod) => mod.getTeamScheduleHandler
);
}
// Unreachable code but required for type safety
if (!UNSTABLE_HANDLER_CACHE.getTeamSchedule) {
throw new Error("Failed to load handler");
}
return UNSTABLE_HANDLER_CACHE.getTeamSchedule({
ctx,
input,
});
}),
});
@@ -0,0 +1,17 @@
import type { IncomingMessage } from "http";
import { getAvailableSlots } from "../slots/util";
import type { TGetTeamScheduleInputSchema } from "./getTeamSchedule.schema";
export type GetTeamScheduleOptions = {
ctx?: ContextForGetSchedule;
input: TGetTeamScheduleInputSchema;
};
interface ContextForGetSchedule extends Record<string, unknown> {
req?: (IncomingMessage & { cookies: Partial<{ [key: string]: string }> }) | undefined;
}
export const getTeamScheduleHandler = async ({ ctx, input }: GetTeamScheduleOptions) => {
return await getAvailableSlots({ ctx, input });
};
@@ -0,0 +1,7 @@
import type { z } from "zod";
import { getScheduleSchema } from "../slots/types";
export const ZGetTeamScheduleInputSchema = getScheduleSchema;
export type TGetTeamScheduleInputSchema = z.infer<typeof ZGetTeamScheduleInputSchema>;