From df4cf7822edb6b303e3a1f89f9cca9f4067bfac3 Mon Sep 17 00:00:00 2001 From: Namekuji Date: Mon, 7 Aug 2023 08:32:29 -0400 Subject: [PATCH] perf: cache acct --- packages/backend/src/misc/cache.ts | 4 +-- packages/backend/src/server/index.ts | 36 ++++++++++++++------- packages/backend/src/services/user-cache.ts | 3 +- 3 files changed, 29 insertions(+), 14 deletions(-) diff --git a/packages/backend/src/misc/cache.ts b/packages/backend/src/misc/cache.ts index 982a4de98d..818edb3279 100644 --- a/packages/backend/src/misc/cache.ts +++ b/packages/backend/src/misc/cache.ts @@ -140,7 +140,7 @@ export class Cache { } } -class SetCache { +export class SetCache { private readonly key: string; private readonly fetchedKey: string; private readonly fetcher: () => Promise; @@ -198,7 +198,7 @@ class SetCache { } } -class HashCache { +export class HashCache { private readonly key: string; private readonly fetchedKey: string; private readonly fetcher: () => Promise>; diff --git a/packages/backend/src/server/index.ts b/packages/backend/src/server/index.ts index 92961d33d2..341d63e529 100644 --- a/packages/backend/src/server/index.ts +++ b/packages/backend/src/server/index.ts @@ -34,6 +34,10 @@ import { initializeStreamingServer } from "./api/streaming.js"; import { koaBody } from "koa-body"; import removeTrailingSlash from "koa-remove-trailing-slashes"; import { v4 as uuid } from "uuid"; +import { + acctToUserIdCache, + userDenormalizedCache, +} from "@/services/user-cache.js"; export const serverLogger = new Logger("server", "gray", false); @@ -109,19 +113,29 @@ router.use(wellKnown.routes()); router.get("/avatar/@:acct", async (ctx) => { const { username, host } = Acct.parse(ctx.params.acct); - const user = await Users.findOne({ - where: { - usernameLower: username.toLowerCase(), - host: host == null || host === config.host ? IsNull() : host, - isSuspended: false, - }, - relations: ["avatar"], - }); + const userId = await acctToUserIdCache.fetchMaybe( + `${username}@${host ?? config.host}`, + () => + Users.findOne({ + where: { + usernameLower: username.toLowerCase(), + host: !host || host === config.host ? IsNull() : host, + isSuspended: false, + }, + }).then((user) => user?.id ?? undefined), + true, + ); - if (user) { - ctx.redirect(Users.getAvatarUrlSync(user)); - } else { + if (!userId) { ctx.redirect("/static-assets/user-unknown.png"); + } else { + const user = await userDenormalizedCache.fetch(userId, () => + Users.findOneOrFail({ + relations: { avatar: true, banner: true }, + where: { id: userId }, + }), + ); + ctx.redirect(Users.getAvatarUrlSync(user)); } }); diff --git a/packages/backend/src/services/user-cache.ts b/packages/backend/src/services/user-cache.ts index 2eff8ba11f..019bae4c1c 100644 --- a/packages/backend/src/services/user-cache.ts +++ b/packages/backend/src/services/user-cache.ts @@ -4,7 +4,7 @@ import type { ILocalUser, } from "@/models/entities/user.js"; import { Users } from "@/models/index.js"; -import { Cache } from "@/misc/cache.js"; +import { Cache, HashCache } from "@/misc/cache.js"; import { redisClient, subscriber } from "@/db/redis.js"; export const userByIdCache = new Cache("userById", 60 * 30); @@ -24,6 +24,7 @@ export const userDenormalizedCache = new Cache( "userDenormalized", 60 * 30, ); +export const acctToUserIdCache = new Cache("acctToUserId", 60 * 60 * 24); subscriber.on("message", async (_, data) => { const obj = JSON.parse(data);