chore: Removing the calendar-cache because of perf issues (#9808)

Co-authored-by: Efraín Rochín <roae.85@gmail.com>
This commit is contained in:
Keith Williams 2023-06-27 00:32:05 +02:00 committed by GitHub
parent 95ce3b215d
commit 4fe69b5864
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 5 additions and 190 deletions

View File

@ -1 +0,0 @@
export { getStaticProps, getStaticPaths, default } from "./index";

View File

@ -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;

View File

@ -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: {

View File

@ -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 });
}

View File

@ -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" });
}
}

View File

@ -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);
}
}
// 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);
} catch (e) {
logger.warn(e);
}
coldStart = false;
return results.reduce((acc, availability) => acc.concat(availability), []);
};

View File

@ -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);
})
);
};

View File

@ -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}`);
}
};