diff --git a/src/server/api/routers/room.ts b/src/server/api/routers/room.ts index 0165fdd..0efdfbc 100644 --- a/src/server/api/routers/room.ts +++ b/src/server/api/routers/room.ts @@ -4,7 +4,7 @@ import { publishToChannel } from "~/server/ably"; import { createTRPCRouter, protectedProcedure } from "~/server/api/trpc"; import { env } from "~/env.mjs"; -import { redis } from "~/server/redis"; +import { fetchCache, invalidateCache, setCache } from "~/server/redis"; export const roomRouter = createTRPCRouter({ // Create @@ -26,8 +26,8 @@ export const roomRouter = createTRPCRouter({ }, }); if (room) { - await redis.del(`${env.APP_ENV}_kv_roomcount_admin`); - await redis.del(`${env.APP_ENV}_kv_roomlist_${ctx.session.user.id}`); + await invalidateCache(`kv_roomcount_admin`); + await invalidateCache(`kv_roomlist_${ctx.session.user.id}`); await publishToChannel( `${ctx.session.user.id}`, @@ -66,13 +66,13 @@ export const roomRouter = createTRPCRouter({ // Get All getAll: protectedProcedure.query(async ({ ctx }) => { - const cachedResult = await redis.get< + const cachedResult = await fetchCache< { id: string; createdAt: Date; roomName: string; }[] - >(`${env.APP_ENV}_kv_roomlist_${ctx.session.user.id}`); + >(`kv_roomlist_${ctx.session.user.id}`); if (cachedResult) { return cachedResult; @@ -88,29 +88,21 @@ export const roomRouter = createTRPCRouter({ }, }); - await redis.set( - `${env.APP_ENV}_kv_roomlist_${ctx.session.user.id}`, - roomList, - { ex: Number(env.UPSTASH_REDIS_EXPIRY_SECONDS) } - ); + await setCache(`kv_roomlist_${ctx.session.user.id}`, roomList); return roomList; } }), countAll: protectedProcedure.query(async ({ ctx }) => { - const cachedResult = await redis.get( - `${env.APP_ENV}_kv_roomcount_admin` - ); + const cachedResult = await fetchCache(`kv_roomcount_admin`); if (cachedResult) { return cachedResult; } else { const roomsCount = await ctx.prisma.room.count(); - await redis.set(`${env.APP_ENV}_kv_roomcount_admin`, roomsCount, { - ex: Number(env.UPSTASH_REDIS_EXPIRY_SECONDS), - }); + await setCache(`kv_roomcount_admin`, roomsCount); return roomsCount; } @@ -176,7 +168,7 @@ export const roomRouter = createTRPCRouter({ }, }); - await redis.del(`${env.APP_ENV}_kv_votes_${input.roomId}`); + await invalidateCache(`kv_votes_${input.roomId}`); } const newRoom = await ctx.prisma.room.update({ @@ -228,9 +220,9 @@ export const roomRouter = createTRPCRouter({ }); if (deletedRoom) { - await redis.del(`${env.APP_ENV}_kv_roomcount_admin`); - await redis.del(`${env.APP_ENV}_kv_votecount_admin`); - await redis.del(`${env.APP_ENV}_kv_roomlist_${ctx.session.user.id}`); + await invalidateCache(`kv_roomcount_admin`); + await invalidateCache(`kv_votecount_admin`); + await invalidateCache(`kv_roomlist_${ctx.session.user.id}`); await publishToChannel( `${ctx.session.user.id}`, diff --git a/src/server/api/routers/session.ts b/src/server/api/routers/session.ts index 6670d32..cb637a5 100644 --- a/src/server/api/routers/session.ts +++ b/src/server/api/routers/session.ts @@ -1,7 +1,7 @@ import { z } from "zod"; import { createTRPCRouter, protectedProcedure } from "~/server/api/trpc"; import { env } from "~/env.mjs"; -import { redis } from "~/server/redis"; +import { invalidateCache } from "~/server/redis"; export const sessionRouter = createTRPCRouter({ deleteAllByUserId: protectedProcedure @@ -18,7 +18,7 @@ export const sessionRouter = createTRPCRouter({ }); if (!!sessions) { - await redis.del(`${env.APP_ENV}_kv_userlist_admin`); + await invalidateCache(`kv_userlist_admin`); } return !!sessions; @@ -27,7 +27,7 @@ export const sessionRouter = createTRPCRouter({ const sessions = await ctx.prisma.session.deleteMany(); if (!!sessions) { - await redis.del(`${env.APP_ENV}_kv_userlist_admin`); + await invalidateCache(`kv_userlist_admin`); } return !!sessions; diff --git a/src/server/api/routers/user.ts b/src/server/api/routers/user.ts index abd5b2a..69e7164 100644 --- a/src/server/api/routers/user.ts +++ b/src/server/api/routers/user.ts @@ -6,24 +6,20 @@ import type { Role } from "~/utils/types"; import { Resend } from "resend"; import { Goodbye } from "~/components/templates/Goodbye"; -import { redis } from "~/server/redis"; +import { setCache, fetchCache, invalidateCache } from "~/server/redis"; const resend = new Resend(process.env.RESEND_API_KEY); export const userRouter = createTRPCRouter({ countAll: protectedProcedure.query(async ({ ctx }) => { - const cachedResult = await redis.get( - `${env.APP_ENV}_kv_usercount_admin` - ); + const cachedResult = await fetchCache(`kv_usercount_admin`); if (cachedResult) { return cachedResult; } else { const usersCount = await ctx.prisma.user.count(); - await redis.set(`${env.APP_ENV}_kv_usercount_admin`, usersCount, { - ex: Number(env.UPSTASH_REDIS_EXPIRY_SECONDS), - }); + await setCache(`kv_usercount_admin`, usersCount); return usersCount; } @@ -48,7 +44,7 @@ export const userRouter = createTRPCRouter({ }); }), getAll: protectedProcedure.query(async ({ ctx }) => { - const cachedResult = await redis.get< + const cachedResult = await fetchCache< { accounts: { provider: string; @@ -62,7 +58,7 @@ export const userRouter = createTRPCRouter({ name: string | null; email: string | null; }[] - >(`${env.APP_ENV}_kv_userlist_admin`); + >(`kv_userlist_admin`); if (cachedResult) { return cachedResult.map((user) => { @@ -92,9 +88,7 @@ export const userRouter = createTRPCRouter({ }, }); - await redis.set(`${env.APP_ENV}_kv_userlist_admin`, users, { - ex: Number(env.UPSTASH_REDIS_EXPIRY_SECONDS), - }); + await setCache(`${env.APP_ENV}_kv_userlist_admin`, users); return users; } @@ -132,8 +126,8 @@ export const userRouter = createTRPCRouter({ react: Goodbye({ name: user.name }), }); - await redis.del(`${env.APP_ENV}_kv_usercount_admin`); - await redis.del(`${env.APP_ENV}_kv_userlist_admin`); + await invalidateCache(`kv_usercount_admin`); + await invalidateCache(`kv_userlist_admin`); } return !!user; @@ -173,7 +167,7 @@ export const userRouter = createTRPCRouter({ }, }); - await redis.del(`${env.APP_ENV}_kv_userlist_admin`); + await invalidateCache(`kv_userlist_admin`); return !!user; }), diff --git a/src/server/api/routers/vote.ts b/src/server/api/routers/vote.ts index 60dd23d..5b0b2fa 100644 --- a/src/server/api/routers/vote.ts +++ b/src/server/api/routers/vote.ts @@ -4,22 +4,18 @@ import { publishToChannel } from "~/server/ably"; import { createTRPCRouter, protectedProcedure } from "~/server/api/trpc"; import { env } from "~/env.mjs"; import type { Room } from "@prisma/client"; -import { redis } from "~/server/redis"; +import { fetchCache, invalidateCache, setCache } from "~/server/redis"; export const voteRouter = createTRPCRouter({ countAll: protectedProcedure.query(async ({ ctx }) => { - const cachedResult = await redis.get( - `${env.APP_ENV}_kv_votecount_admin` - ); + const cachedResult = await fetchCache(`kv_votecount_admin`); if (cachedResult) { return cachedResult; } else { const votesCount = await ctx.prisma.vote.count(); - await redis.set(`${env.APP_ENV}_kv_votecount_admin`, votesCount, { - ex: Number(env.UPSTASH_REDIS_EXPIRY_SECONDS), - }); + await setCache(`kv_votecount_admin`, votesCount); return votesCount; } @@ -27,7 +23,7 @@ export const voteRouter = createTRPCRouter({ getAllByRoomId: protectedProcedure .input(z.object({ roomId: z.string() })) .query(async ({ ctx, input }) => { - const cachedResult = await redis.get< + const cachedResult = await fetchCache< { value: string; room: Room; @@ -39,7 +35,7 @@ export const voteRouter = createTRPCRouter({ }; roomId: string; }[] - >(`${env.APP_ENV}_kv_votes_${input.roomId}`); + >(`kv_votes_${input.roomId}`); if (cachedResult) { return cachedResult; @@ -63,11 +59,7 @@ export const voteRouter = createTRPCRouter({ }, }); - await redis.set( - `${env.APP_ENV}_kv_votes_${input.roomId}`, - votesByRoomId, - { ex: Number(env.UPSTASH_REDIS_EXPIRY_SECONDS) } - ); + await setCache(`kv_votes_${input.roomId}`, votesByRoomId); return votesByRoomId; } @@ -106,8 +98,8 @@ export const voteRouter = createTRPCRouter({ }); if (vote) { - await redis.del(`${env.APP_ENV}_kv_votecount_admin`); - await redis.del(`${env.APP_ENV}_kv_votes_${input.roomId}`); + await invalidateCache(`kv_votecount_admin`); + await invalidateCache(`kv_votes_${input.roomId}`); await publishToChannel(`${vote.roomId}`, "VOTE_UPDATE", "UPDATE"); } diff --git a/src/server/api/trpc.ts b/src/server/api/trpc.ts index cc1c135..067a112 100644 --- a/src/server/api/trpc.ts +++ b/src/server/api/trpc.ts @@ -19,9 +19,10 @@ import { type Session } from "next-auth"; import { getServerAuthSession } from "~/server/auth"; import { prisma } from "~/server/db"; +import { Redis } from "@upstash/redis"; const rateLimit = new Ratelimit({ - redis, + redis: Redis.fromEnv(), limiter: Ratelimit.slidingWindow( Number(env.UPSTASH_RATELIMIT_REQUESTS), `${Number(env.UPSTASH_RATELIMIT_SECONDS)}s` @@ -75,7 +76,6 @@ export const createTRPCContext = async (opts: CreateNextContextOptions) => { import { initTRPC, TRPCError } from "@trpc/server"; import superjson from "superjson"; import { Ratelimit } from "@upstash/ratelimit"; -import { redis } from "../redis"; import { env } from "~/env.mjs"; const t = initTRPC.context().create({ diff --git a/src/server/auth.ts b/src/server/auth.ts index 2e28f7f..c2c3b7d 100644 --- a/src/server/auth.ts +++ b/src/server/auth.ts @@ -12,7 +12,7 @@ import { prisma } from "~/server/db"; import type { Role } from "~/utils/types"; import { Resend } from "resend"; import { Welcome } from "../components/templates/Welcome"; -import { redis } from "./redis"; +import { invalidateCache } from "./redis"; const resend = new Resend(process.env.RESEND_API_KEY); @@ -61,15 +61,15 @@ export const authOptions: NextAuthOptions = { react: Welcome({ name: user.name }), }); - await redis.del(`${env.APP_ENV}_kv_userlist_admin`); - await redis.del(`${env.APP_ENV}_kv_usercount_admin`); + await invalidateCache(`kv_userlist_admin`); + await invalidateCache(`kv_usercount_admin`); } }, async signIn({}) { - await redis.del(`${env.APP_ENV}_kv_userlist_admin`); + await invalidateCache(`kv_userlist_admin`); }, async signOut() { - await redis.del(`${env.APP_ENV}_kv_userlist_admin`); + await invalidateCache(`kv_userlist_admin`); }, }, // @ts-ignore This adapter should work... diff --git a/src/server/redis.ts b/src/server/redis.ts index 2f599b4..f09bb20 100644 --- a/src/server/redis.ts +++ b/src/server/redis.ts @@ -1,6 +1,42 @@ import { Redis } from "@upstash/redis"; import https from "https"; +import { env } from "~/env.mjs"; export const redis = Redis.fromEnv({ agent: new https.Agent({ keepAlive: true }), }); + +export const setCache = async (key: string, value: T) => { + try { + await redis.set(`${env.APP_ENV}_${key}`, value, { + ex: Number(env.UPSTASH_REDIS_EXPIRY_SECONDS), + }); + return true; + } catch { + return false; + } +}; + +export const fetchCache = async (key: string) => { + try { + const result = await redis.get(`${env.APP_ENV}_${key}`); + if (result) { + console.log("CACHE HIT"); + } else { + console.log("CACHE MISS"); + } + return result as T; + } catch { + console.log("CACHE ERROR"); + return null; + } +}; + +export const invalidateCache = async (key: string) => { + try { + await redis.del(`${env.APP_ENV}_${key}`); + return true; + } catch { + return false; + } +};