perf: offload long running tasks to workers, preloading dm page data

This commit is contained in:
Samuel 2024-12-19 16:44:27 +01:00
parent cad305aa66
commit df218b9a56
18 changed files with 524 additions and 297 deletions

View file

@ -1,82 +1,37 @@
import { getDateList, getHourList, getMonthList, getWeekdayList } from "./date";
import type { MessageOverview, MessageStats, Recipients } from "~/types";
import { isSameDay } from "date-fns";
import { cached } from "./db-cache";
import { getHourList, getMonthList, getWeekdayList } from "./date";
import MessageStatsWorker from "./messages-worker?worker";
export const hourNames = getHourList();
const initialHoursMap = [...hourNames.keys()];
export const monthNames = getMonthList();
const initialMonthMap = [...monthNames.keys()];
export const weekdayNames = getWeekdayList();
const initialWeekdayMap = [...weekdayNames.keys()];
const messageStatsWorker = new MessageStatsWorker();
const createMessageStatsSourcesRaw = (messageOverview: MessageOverview, recipients: Recipients) => {
const initialRecipientMap = () => {
return Object.fromEntries(recipients.map(({ recipientId }) => [recipientId, 0]));
};
export const createMessageStatsSources = cached(
(dmId: number, messageOverview: MessageOverview, recipients: Recipients) => {
messageStatsWorker.postMessage({
dmId,
messageOverview,
recipients,
});
const dateList = () => {
const firstDate = messageOverview?.at(0)?.messageDate;
const lastDate = messageOverview?.at(-1)?.messageDate;
if (firstDate && lastDate) {
return getDateList(firstDate, lastDate).map((date) => ({
totalMessages: 0,
date,
...initialRecipientMap(),
}));
}
};
return new Promise<MessageStats>((resolve) => {
const listener = (
event: MessageEvent<{
dmId: number;
messageStatsSources: MessageStats;
}>,
) => {
if (event.data.dmId === dmId) {
resolve(event.data.messageStatsSources);
}
};
const currentDateList = dateList();
const currentInitialRecipientMap = initialRecipientMap();
const messageStats: MessageStats = {
person: { ...currentInitialRecipientMap },
month: initialMonthMap.map(() => ({ ...currentInitialRecipientMap })),
date: currentDateList ?? [],
weekday: initialWeekdayMap.map(() => ({ ...currentInitialRecipientMap })),
daytime: initialHoursMap.map(() => ({ ...currentInitialRecipientMap })),
};
if (currentDateList) {
const { person, month, date, weekday, daytime } = messageStats;
for (const message of messageOverview) {
const { messageDate } = message;
// increment overall message count of a person
person[message.fromRecipientId] += 1;
// increment the message count of the message's month for this recipient
month[messageDate.getMonth()][message.fromRecipientId] += 1;
// biome-ignore lint/style/noNonNullAssertion: <explanation>
const dateStatsEntry = date.find(({ date }) => isSameDay(date, messageDate))!;
// increment the message count of the message's date for this recipient
dateStatsEntry[message.fromRecipientId] += 1;
// increment the overall message count of the message's date
dateStatsEntry.totalMessages += 1;
const weekdayOfDate = messageDate.getDay();
// we index starting with monday while the `Date` object indexes starting with Sunday
const weekdayIndex = weekdayOfDate === 0 ? 6 : weekdayOfDate - 1;
// increment the message count of the message's weekday for this recipient
weekday[weekdayIndex][message.fromRecipientId] += 1;
// increment the message count of the message's daytime for this recipient
daytime[messageDate.getHours()][message.fromRecipientId] += 1;
}
}
return messageStats;
};
export const createMessageStatsSources = cached(createMessageStatsSourcesRaw);
messageStatsWorker.addEventListener("message", listener);
});
},
);