perf: New getTeamSchedule route with higher vCPUs (#17277)
This commit is contained in:
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);
|
||||
@@ -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);
|
||||
};
|
||||
@@ -13,6 +13,7 @@ export const ENDPOINTS = [
|
||||
"dsync",
|
||||
"eventTypes",
|
||||
"features",
|
||||
"highPerf",
|
||||
"insights",
|
||||
"payments",
|
||||
"public",
|
||||
|
||||
@@ -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>;
|
||||
Reference in new issue
Block a user