remove caching from resumes

This commit is contained in:
Amruth Pillai
2024-03-10 10:00:51 +01:00
parent 359c7f1c80
commit 783af5070d
6 changed files with 62 additions and 83 deletions

View File

@ -2,7 +2,7 @@
import { lingui } from "@lingui/vite-plugin"; import { lingui } from "@lingui/vite-plugin";
import { nxViteTsPaths } from "@nx/vite/plugins/nx-tsconfig-paths.plugin"; import { nxViteTsPaths } from "@nx/vite/plugins/nx-tsconfig-paths.plugin";
import react from "@vitejs/plugin-react-swc"; import react from "@vitejs/plugin-react";
import { defineConfig, searchForWorkspaceRoot, splitVendorChunkPlugin } from "vite"; import { defineConfig, searchForWorkspaceRoot, splitVendorChunkPlugin } from "vite";
export default defineConfig({ export default defineConfig({
@ -32,7 +32,9 @@ export default defineConfig({
plugins: [ plugins: [
react({ react({
plugins: [["@lingui/swc-plugin", {}]], babel: {
plugins: ["macros"],
},
}), }),
lingui(), lingui(),
nxViteTsPaths(), nxViteTsPaths(),

View File

@ -48,52 +48,42 @@ export class PrinterService {
} }
async printResume(resume: ResumeDto) { async printResume(resume: ResumeDto) {
return this.utils.getCachedOrSet( const start = performance.now();
`user:${resume.userId}:storage:resumes:${resume.id}`,
async () => {
const start = performance.now();
const url = await retry(() => this.generateResume(resume), { const url = await retry(() => this.generateResume(resume), {
retries: 3, retries: 3,
randomize: true, randomize: true,
onRetry: (_, attempt) => { onRetry: (_, attempt) => {
this.logger.log(`Retrying to print resume #${resume.id}, attempt #${attempt}`); this.logger.log(`Retrying to print resume #${resume.id}, attempt #${attempt}`);
},
});
const duration = Number(performance.now() - start).toFixed(0);
const numPages = resume.data.metadata.layout.length;
this.logger.debug(`Chrome took ${duration}ms to print ${numPages} page(s)`);
return url;
}, },
); });
const duration = Number(performance.now() - start).toFixed(0);
const numPages = resume.data.metadata.layout.length;
this.logger.debug(`Chrome took ${duration}ms to print ${numPages} page(s)`);
return url;
} }
async printPreview(resume: ResumeDto) { async printPreview(resume: ResumeDto) {
return this.utils.getCachedOrSet( const start = performance.now();
`user:${resume.userId}:storage:previews:${resume.id}`,
async () => {
const start = performance.now();
const url = await retry(() => this.generatePreview(resume), { const url = await retry(() => this.generatePreview(resume), {
retries: 3, retries: 3,
randomize: true, randomize: true,
onRetry: (_, attempt) => { onRetry: (_, attempt) => {
this.logger.log( this.logger.log(
`Retrying to generate preview of resume #${resume.id}, attempt #${attempt}`, `Retrying to generate preview of resume #${resume.id}, attempt #${attempt}`,
); );
},
});
const duration = Number(performance.now() - start).toFixed(0);
this.logger.debug(`Chrome took ${duration}ms to generate preview`);
return url;
}, },
); });
const duration = Number(performance.now() - start).toFixed(0);
this.logger.debug(`Chrome took ${duration}ms to generate preview`);
return url;
} }
async generateResume(resume: ResumeDto) { async generateResume(resume: ResumeDto) {

View File

@ -115,7 +115,7 @@ export class ResumeController {
@Patch(":id/lock") @Patch(":id/lock")
@UseGuards(TwoFactorGuard) @UseGuards(TwoFactorGuard)
lock(@User() user: UserEntity, @Param("id") id: string, @Body("set") set: boolean = true) { lock(@User() user: UserEntity, @Param("id") id: string, @Body("set") set = true) {
return this.resumeService.lock(user.id, id, set); return this.resumeService.lock(user.id, id, set);
} }

View File

@ -54,10 +54,10 @@ export class ResumeService {
}, },
}); });
await Promise.all([ // await Promise.all([
this.redis.del(`user:${userId}:resumes`), // this.redis.del(`user:${userId}:resumes`),
this.redis.set(`user:${userId}:resume:${resume.id}`, JSON.stringify(resume)), // this.redis.set(`user:${userId}:resume:${resume.id}`, JSON.stringify(resume)),
]); // ]);
return resume; return resume;
} }
@ -75,37 +75,24 @@ export class ResumeService {
}, },
}); });
await Promise.all([ // await Promise.all([
this.redis.del(`user:${userId}:resumes`), // this.redis.del(`user:${userId}:resumes`),
this.redis.set(`user:${userId}:resume:${resume.id}`, JSON.stringify(resume)), // this.redis.set(`user:${userId}:resume:${resume.id}`, JSON.stringify(resume)),
]); // ]);
return resume; return resume;
} }
findAll(userId: string) { findAll(userId: string) {
return this.utils.getCachedOrSet(`user:${userId}:resumes`, () => return this.prisma.resume.findMany({ where: { userId }, orderBy: { updatedAt: "desc" } });
this.prisma.resume.findMany({
where: { userId },
orderBy: { updatedAt: "desc" },
}),
);
} }
findOne(id: string, userId?: string) { findOne(id: string, userId?: string) {
if (userId) { if (userId) {
return this.utils.getCachedOrSet(`user:${userId}:resume:${id}`, () => return this.prisma.resume.findUniqueOrThrow({ where: { userId_id: { userId, id } } });
this.prisma.resume.findUniqueOrThrow({
where: { userId_id: { userId, id } },
}),
);
} }
return this.utils.getCachedOrSet(`user:public:resume:${id}`, () => return this.prisma.resume.findUniqueOrThrow({ where: { id } });
this.prisma.resume.findUniqueOrThrow({
where: { id },
}),
);
} }
async findOneStatistics(userId: string, id: string) { async findOneStatistics(userId: string, id: string) {
@ -149,12 +136,12 @@ export class ResumeService {
where: { userId_id: { userId, id } }, where: { userId_id: { userId, id } },
}); });
await Promise.all([ // await Promise.all([
this.redis.set(`user:${userId}:resume:${id}`, JSON.stringify(resume)), // this.redis.set(`user:${userId}:resume:${id}`, JSON.stringify(resume)),
this.redis.del(`user:${userId}:resumes`), // this.redis.del(`user:${userId}:resumes`),
this.redis.del(`user:${userId}:storage:resumes:${id}`), // this.redis.del(`user:${userId}:storage:resumes:${id}`),
this.redis.del(`user:${userId}:storage:previews:${id}`), // this.redis.del(`user:${userId}:storage:previews:${id}`),
]); // ]);
return resume; return resume;
} catch (error) { } catch (error) {
@ -171,10 +158,10 @@ export class ResumeService {
where: { userId_id: { userId, id } }, where: { userId_id: { userId, id } },
}); });
await Promise.all([ // await Promise.all([
this.redis.set(`user:${userId}:resume:${id}`, JSON.stringify(resume)), // this.redis.set(`user:${userId}:resume:${id}`, JSON.stringify(resume)),
this.redis.del(`user:${userId}:resumes`), // this.redis.del(`user:${userId}:resumes`),
]); // ]);
return resume; return resume;
} }
@ -182,8 +169,8 @@ export class ResumeService {
async remove(userId: string, id: string) { async remove(userId: string, id: string) {
await Promise.all([ await Promise.all([
// Remove cached keys // Remove cached keys
this.redis.del(`user:${userId}:resumes`), // this.redis.del(`user:${userId}:resumes`),
this.redis.del(`user:${userId}:resume:${id}`), // this.redis.del(`user:${userId}:resume:${id}`),
// Remove files in storage, and their cached keys // Remove files in storage, and their cached keys
this.storageService.deleteObject(userId, "resumes", id), this.storageService.deleteObject(userId, "resumes", id),

View File

@ -1,5 +1,5 @@
import { type Dispatch, type SetStateAction, useEffect, useState } from "react"; import { type Dispatch, type SetStateAction, useEffect, useState } from "react";
import { useLocalStorage, useMediaQuery, useUpdateEffect } from "usehooks-ts"; import { useLocalStorage, useMediaQuery } from "usehooks-ts";
const COLOR_SCHEME_QUERY = "(prefers-color-scheme: dark)"; const COLOR_SCHEME_QUERY = "(prefers-color-scheme: dark)";
@ -17,9 +17,9 @@ export const useTheme = (): UseThemeOutput => {
const [isDarkMode, setDarkMode] = useState<boolean>(isDarkOS); const [isDarkMode, setDarkMode] = useState<boolean>(isDarkOS);
const [theme, setTheme] = useLocalStorage<Theme>("theme", "system"); const [theme, setTheme] = useLocalStorage<Theme>("theme", "system");
useUpdateEffect(() => { useEffect(() => {
if (theme === "system") setDarkMode(isDarkOS); if (theme === "system") setDarkMode((prev) => !prev);
}, [isDarkOS]); }, [theme]);
useEffect(() => { useEffect(() => {
switch (theme) { switch (theme) {

View File

@ -34,7 +34,7 @@ import { Link } from "@tiptap/extension-link";
import { TextAlign } from "@tiptap/extension-text-align"; import { TextAlign } from "@tiptap/extension-text-align";
import { Underline } from "@tiptap/extension-underline"; import { Underline } from "@tiptap/extension-underline";
import { Editor, EditorContent, EditorContentProps, useEditor } from "@tiptap/react"; import { Editor, EditorContent, EditorContentProps, useEditor } from "@tiptap/react";
import { StarterKit } from "@tiptap/starter-kit"; import StarterKit from "@tiptap/starter-kit";
import { forwardRef, useCallback } from "react"; import { forwardRef, useCallback } from "react";
import { useForm } from "react-hook-form"; import { useForm } from "react-hook-form";
import { z } from "zod"; import { z } from "zod";