chore: Removing the calendar-cache because of perf issues (#9808)
Co-authored-by: Efraín Rochín <roae.85@gmail.com>pull/9629/head^2
parent
95ce3b215d
commit
4fe69b5864
|
@ -1 +0,0 @@
|
|||
export { getStaticProps, getStaticPaths, default } from "./index";
|
|
@ -1,69 +0,0 @@
|
|||
/**
|
||||
* This page is empty for the user, it is used only to take advantage of the
|
||||
* caching system that NextJS uses SSG pages.
|
||||
* TODO: Redirect to user profile on browser
|
||||
*/
|
||||
import type { GetStaticPaths, GetStaticProps, InferGetStaticPropsType } from "next";
|
||||
import { z } from "zod";
|
||||
|
||||
import getCalendarsEvents from "@calcom/core/getCalendarsEvents";
|
||||
import dayjs from "@calcom/dayjs";
|
||||
import prisma from "@calcom/prisma";
|
||||
|
||||
const paramsSchema = z.object({ user: z.string(), month: z.string() });
|
||||
export const getStaticProps: GetStaticProps<
|
||||
{ results: Awaited<ReturnType<typeof getCalendarsEvents>> },
|
||||
{ user: string }
|
||||
> = async (context) => {
|
||||
const { user: username, month } = paramsSchema.parse(context.params);
|
||||
const userWithCredentials = await prisma.user.findFirst({
|
||||
where: {
|
||||
username,
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
username: true,
|
||||
credentials: true,
|
||||
selectedCalendars: true,
|
||||
},
|
||||
});
|
||||
// Subtract 11 hours from the start date to avoid problems in UTC- time zones.
|
||||
const startDate = dayjs.utc(month, "YYYY-MM").startOf("day").subtract(11, "hours").format();
|
||||
// Add 14 hours from the start date to avoid problems in UTC+ time zones.
|
||||
const endDate = dayjs.utc(month, "YYYY-MM").endOf("month").add(14, "hours").format();
|
||||
try {
|
||||
const results = userWithCredentials?.credentials
|
||||
? await getCalendarsEvents(
|
||||
userWithCredentials?.credentials,
|
||||
startDate,
|
||||
endDate,
|
||||
userWithCredentials?.selectedCalendars
|
||||
)
|
||||
: [];
|
||||
|
||||
return {
|
||||
props: { results, date: new Date().toISOString() },
|
||||
revalidate: 1,
|
||||
};
|
||||
} catch (error) {
|
||||
let message = "Unknown error while fetching calendar";
|
||||
if (error instanceof Error) message = error.message;
|
||||
console.error(error, message);
|
||||
return {
|
||||
props: { results: [], date: new Date().toISOString(), message },
|
||||
revalidate: 1,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
export const getStaticPaths: GetStaticPaths = () => {
|
||||
return {
|
||||
paths: [],
|
||||
fallback: "blocking",
|
||||
};
|
||||
};
|
||||
type Props = InferGetStaticPropsType<typeof getStaticProps>;
|
||||
const CalendarCache = (props: Props) =>
|
||||
process.env.NODE_ENV === "development" ? <pre>{JSON.stringify(props, null, " ")}</pre> : <div />;
|
||||
|
||||
export default CalendarCache;
|
|
@ -4,7 +4,6 @@ import { z } from "zod";
|
|||
import { getCalendarCredentials, getConnectedCalendars } from "@calcom/core/CalendarManager";
|
||||
import { getServerSession } from "@calcom/features/auth/lib/getServerSession";
|
||||
import notEmpty from "@calcom/lib/notEmpty";
|
||||
import { revalidateCalendarCache } from "@calcom/lib/server/revalidateCalendarCache";
|
||||
import prisma from "@calcom/prisma";
|
||||
|
||||
const selectedCalendarSelectSchema = z.object({
|
||||
|
@ -73,10 +72,6 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
|||
res.status(200).json({ message: "Calendar Selection Saved" });
|
||||
}
|
||||
|
||||
if (["DELETE", "POST"].includes(req.method)) {
|
||||
await revalidateCalendarCache(res.revalidate, `${session?.user?.username}`);
|
||||
}
|
||||
|
||||
if (req.method === "GET") {
|
||||
const selectedCalendarIds = await prisma.selectedCalendar.findMany({
|
||||
where: {
|
||||
|
|
|
@ -5,7 +5,6 @@ import getInstalledAppPath from "@calcom/app-store/_utils/getInstalledAppPath";
|
|||
import { getServerSession } from "@calcom/features/auth/lib/getServerSession";
|
||||
import { deriveAppDictKeyFromType } from "@calcom/lib/deriveAppDictKeyFromType";
|
||||
import { HttpError } from "@calcom/lib/http-error";
|
||||
import { revalidateCalendarCache } from "@calcom/lib/server/revalidateCalendarCache";
|
||||
import prisma from "@calcom/prisma";
|
||||
import type { AppDeclarativeHandler, AppHandler } from "@calcom/types/AppHandler";
|
||||
|
||||
|
@ -62,14 +61,8 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
|||
|
||||
if (typeof handler === "function") {
|
||||
await handler(req, res);
|
||||
if (appName.includes("calendar") && req.session?.user?.username) {
|
||||
await revalidateCalendarCache(res.revalidate, req.session?.user?.username);
|
||||
}
|
||||
} else {
|
||||
await defaultIntegrationAddHandler({ user: req.session?.user, ...handler });
|
||||
if (handler.appType.includes("calendar") && req.session?.user?.username) {
|
||||
await revalidateCalendarCache(res.revalidate, req.session?.user?.username);
|
||||
}
|
||||
redirectUrl = handler.redirect?.url || getInstalledAppPath(handler);
|
||||
res.json({ url: redirectUrl, newTab: handler.redirect?.newTab });
|
||||
}
|
||||
|
|
|
@ -1,27 +0,0 @@
|
|||
import type { NextApiRequest, NextApiResponse } from "next";
|
||||
import { z } from "zod";
|
||||
|
||||
import { revalidateCalendarCache } from "@calcom/lib/server/revalidateCalendarCache";
|
||||
|
||||
const querySchema = z.object({
|
||||
username: z.string(),
|
||||
});
|
||||
|
||||
/**
|
||||
* This endpoint revalidates users calendar cache several months ahead
|
||||
* Can be used as webhook
|
||||
* @param req
|
||||
* @param res
|
||||
* @returns
|
||||
*/
|
||||
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
const { username } = querySchema.parse(req.query);
|
||||
try {
|
||||
await revalidateCalendarCache(res.revalidate, username);
|
||||
|
||||
return res.status(200).json({ revalidated: true });
|
||||
} catch (err) {
|
||||
return res.status(500).send({ message: "Error revalidating" });
|
||||
}
|
||||
}
|
|
@ -1,12 +1,10 @@
|
|||
import type { SelectedCalendar } from "@prisma/client";
|
||||
import { sortBy } from "lodash";
|
||||
import * as process from "process";
|
||||
|
||||
import { getCalendar } from "@calcom/app-store/_utils/getCalendar";
|
||||
import getApps from "@calcom/app-store/utils";
|
||||
import dayjs from "@calcom/dayjs";
|
||||
import { getUid } from "@calcom/lib/CalEventParser";
|
||||
import { WEBAPP_URL } from "@calcom/lib/constants";
|
||||
import logger from "@calcom/lib/logger";
|
||||
import { performance } from "@calcom/lib/server/perfObserver";
|
||||
import type {
|
||||
|
@ -21,7 +19,6 @@ import type { EventResult } from "@calcom/types/EventManager";
|
|||
import getCalendarsEvents from "./getCalendarsEvents";
|
||||
|
||||
const log = logger.getChildLogger({ prefix: ["CalendarManager"] });
|
||||
let coldStart = true;
|
||||
|
||||
export const getCalendarCredentials = (credentials: Array<CredentialPayload>) => {
|
||||
const calendarCredentials = getApps(credentials)
|
||||
|
@ -179,35 +176,6 @@ export const getCachedResults = async (
|
|||
return awaitedResults as any;
|
||||
};
|
||||
|
||||
/**
|
||||
* This function fetch the json file that NextJS generates and uses to hydrate the static page on browser.
|
||||
* If for some reason NextJS still doesn't generate this file, it will wait until it finishes generating it.
|
||||
* On development environment it takes a long time because Next must compiles the whole page.
|
||||
* @param username
|
||||
* @param month A string representing year and month using YYYY-MM format
|
||||
* @param organizationSlug A string with the organization slug
|
||||
*/
|
||||
const getNextCache = async (
|
||||
username: string,
|
||||
month: string,
|
||||
organizationSlug?: string | null
|
||||
): Promise<EventBusyDate[][]> => {
|
||||
let localCache: EventBusyDate[][] = [];
|
||||
const { NODE_ENV } = process.env;
|
||||
const cacheDir = `${NODE_ENV === "development" ? NODE_ENV : process.env.BUILD_ID}`;
|
||||
const baseUrl = `${WEBAPP_URL}/_next/data/${cacheDir}/en`;
|
||||
const url = organizationSlug
|
||||
? `${baseUrl}/${username}/calendar-cache/${month}/${organizationSlug}.json?user=${username}&month=${month}&orgSlug=${organizationSlug}`
|
||||
: `${baseUrl}/${username}/calendar-cache/${month}.json?user=${username}&month=${month}`;
|
||||
try {
|
||||
localCache = await fetch(url)
|
||||
.then((r) => r.json())
|
||||
.then((json) => json?.pageProps?.results);
|
||||
} catch (e) {
|
||||
log.warn(url, e);
|
||||
}
|
||||
return localCache;
|
||||
};
|
||||
/**
|
||||
* Get months between given dates
|
||||
* @returns ["2023-04", "2024-05"]
|
||||
|
@ -225,11 +193,6 @@ const getMonths = (dateFrom: string, dateTo: string): string[] => {
|
|||
return months;
|
||||
};
|
||||
|
||||
const createCalendarCachePage = (username: string, month: string, organizationSlug?: string | null): void => {
|
||||
// No need to wait for this, the purpose is to force re-validation every second as indicated
|
||||
// in page getStaticProps.
|
||||
fetch(`${WEBAPP_URL}/${username}/calendar-cache/${month}/${organizationSlug}`).catch(console.log);
|
||||
};
|
||||
export const getBusyCalendarTimes = async (
|
||||
username: string,
|
||||
withCredentials: CredentialPayload[],
|
||||
|
@ -241,30 +204,14 @@ export const getBusyCalendarTimes = async (
|
|||
let results: EventBusyDate[][] = [];
|
||||
const months = getMonths(dateFrom, dateTo);
|
||||
try {
|
||||
if (coldStart) {
|
||||
// Subtract 11 hours from the start date to avoid problems in UTC- time zones.
|
||||
const startDate = dayjs(dateFrom).subtract(11, "hours").format();
|
||||
// Add 14 hours from the start date to avoid problems in UTC+ time zones.
|
||||
const endDate = dayjs(dateTo).endOf("month").add(14, "hours").format();
|
||||
results = await getCalendarsEvents(withCredentials, startDate, endDate, selectedCalendars);
|
||||
console.log("Generating calendar cache in background");
|
||||
// on cold start the calendar cache page generated in the background
|
||||
Promise.all(months.map((month) => createCalendarCachePage(username, month, organizationSlug)));
|
||||
} else {
|
||||
if (months.length === 1) {
|
||||
results = await getNextCache(username, dayjs(dateFrom).format("YYYY-MM"), organizationSlug);
|
||||
} else {
|
||||
// if dateFrom and dateTo is from different months get cache by each month
|
||||
const data: EventBusyDate[][][] = await Promise.all(
|
||||
months.map((month) => getNextCache(username, month, organizationSlug))
|
||||
);
|
||||
results = data.flat(1);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
logger.warn(e);
|
||||
}
|
||||
coldStart = false;
|
||||
return results.reduce((acc, availability) => acc.concat(availability), []);
|
||||
};
|
||||
|
||||
|
|
|
@ -1,18 +0,0 @@
|
|||
import type { NextApiResponse } from "next";
|
||||
|
||||
import dayjs from "@calcom/dayjs";
|
||||
|
||||
export const revalidateCalendarCache = (
|
||||
revalidate: NextApiResponse["revalidate"],
|
||||
username: string,
|
||||
monthsToRevalidate = 4
|
||||
): Promise<void[]> => {
|
||||
return Promise.all(
|
||||
new Array(monthsToRevalidate).fill(0).map((_, index): Promise<void> => {
|
||||
const date = dayjs().add(index, "month").format("YYYY-MM");
|
||||
const url = `/${username}/calendar-cache/${date}`;
|
||||
console.log("revalidating", url);
|
||||
return revalidate(url);
|
||||
})
|
||||
);
|
||||
};
|
|
@ -5,7 +5,6 @@ import { DailyLocationType } from "@calcom/core/location";
|
|||
import { sendCancelledEmails } from "@calcom/emails";
|
||||
import { getCalEventResponses } from "@calcom/features/bookings/lib/getCalEventResponses";
|
||||
import { isPrismaObjOrUndefined, parseRecurringEvent } from "@calcom/lib";
|
||||
import { WEBAPP_URL } from "@calcom/lib/constants";
|
||||
import getPaymentAppData from "@calcom/lib/getPaymentAppData";
|
||||
import { deletePayment } from "@calcom/lib/payment/deletePayment";
|
||||
import { getTranslation } from "@calcom/lib/server/i18n";
|
||||
|
@ -344,8 +343,4 @@ export const deleteCredentialHandler = async ({ ctx, input }: DeleteCredentialOp
|
|||
id: id,
|
||||
},
|
||||
});
|
||||
// Revalidate user calendar cache.
|
||||
if (credential.app?.slug.includes("calendar")) {
|
||||
await fetch(`${WEBAPP_URL}/api/revalidate-calendar-cache/${ctx?.user?.username}`);
|
||||
}
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue