Redis overhaul
This commit is contained in:
parent
f5cdf2992c
commit
236c34e85d
7 changed files with 75 additions and 61 deletions
|
@ -4,7 +4,7 @@ import { publishToChannel } from "~/server/ably";
|
||||||
import { createTRPCRouter, protectedProcedure } from "~/server/api/trpc";
|
import { createTRPCRouter, protectedProcedure } from "~/server/api/trpc";
|
||||||
|
|
||||||
import { env } from "~/env.mjs";
|
import { env } from "~/env.mjs";
|
||||||
import { redis } from "~/server/redis";
|
import { fetchCache, invalidateCache, setCache } from "~/server/redis";
|
||||||
|
|
||||||
export const roomRouter = createTRPCRouter({
|
export const roomRouter = createTRPCRouter({
|
||||||
// Create
|
// Create
|
||||||
|
@ -26,8 +26,8 @@ export const roomRouter = createTRPCRouter({
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
if (room) {
|
if (room) {
|
||||||
await redis.del(`${env.APP_ENV}_kv_roomcount_admin`);
|
await invalidateCache(`kv_roomcount_admin`);
|
||||||
await redis.del(`${env.APP_ENV}_kv_roomlist_${ctx.session.user.id}`);
|
await invalidateCache(`kv_roomlist_${ctx.session.user.id}`);
|
||||||
|
|
||||||
await publishToChannel(
|
await publishToChannel(
|
||||||
`${ctx.session.user.id}`,
|
`${ctx.session.user.id}`,
|
||||||
|
@ -66,13 +66,13 @@ export const roomRouter = createTRPCRouter({
|
||||||
|
|
||||||
// Get All
|
// Get All
|
||||||
getAll: protectedProcedure.query(async ({ ctx }) => {
|
getAll: protectedProcedure.query(async ({ ctx }) => {
|
||||||
const cachedResult = await redis.get<
|
const cachedResult = await fetchCache<
|
||||||
{
|
{
|
||||||
id: string;
|
id: string;
|
||||||
createdAt: Date;
|
createdAt: Date;
|
||||||
roomName: string;
|
roomName: string;
|
||||||
}[]
|
}[]
|
||||||
>(`${env.APP_ENV}_kv_roomlist_${ctx.session.user.id}`);
|
>(`kv_roomlist_${ctx.session.user.id}`);
|
||||||
|
|
||||||
if (cachedResult) {
|
if (cachedResult) {
|
||||||
return cachedResult;
|
return cachedResult;
|
||||||
|
@ -88,29 +88,21 @@ export const roomRouter = createTRPCRouter({
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
await redis.set(
|
await setCache(`kv_roomlist_${ctx.session.user.id}`, roomList);
|
||||||
`${env.APP_ENV}_kv_roomlist_${ctx.session.user.id}`,
|
|
||||||
roomList,
|
|
||||||
{ ex: Number(env.UPSTASH_REDIS_EXPIRY_SECONDS) }
|
|
||||||
);
|
|
||||||
|
|
||||||
return roomList;
|
return roomList;
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
|
|
||||||
countAll: protectedProcedure.query(async ({ ctx }) => {
|
countAll: protectedProcedure.query(async ({ ctx }) => {
|
||||||
const cachedResult = await redis.get<number>(
|
const cachedResult = await fetchCache<number>(`kv_roomcount_admin`);
|
||||||
`${env.APP_ENV}_kv_roomcount_admin`
|
|
||||||
);
|
|
||||||
|
|
||||||
if (cachedResult) {
|
if (cachedResult) {
|
||||||
return cachedResult;
|
return cachedResult;
|
||||||
} else {
|
} else {
|
||||||
const roomsCount = await ctx.prisma.room.count();
|
const roomsCount = await ctx.prisma.room.count();
|
||||||
|
|
||||||
await redis.set(`${env.APP_ENV}_kv_roomcount_admin`, roomsCount, {
|
await setCache(`kv_roomcount_admin`, roomsCount);
|
||||||
ex: Number(env.UPSTASH_REDIS_EXPIRY_SECONDS),
|
|
||||||
});
|
|
||||||
|
|
||||||
return 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({
|
const newRoom = await ctx.prisma.room.update({
|
||||||
|
@ -228,9 +220,9 @@ export const roomRouter = createTRPCRouter({
|
||||||
});
|
});
|
||||||
|
|
||||||
if (deletedRoom) {
|
if (deletedRoom) {
|
||||||
await redis.del(`${env.APP_ENV}_kv_roomcount_admin`);
|
await invalidateCache(`kv_roomcount_admin`);
|
||||||
await redis.del(`${env.APP_ENV}_kv_votecount_admin`);
|
await invalidateCache(`kv_votecount_admin`);
|
||||||
await redis.del(`${env.APP_ENV}_kv_roomlist_${ctx.session.user.id}`);
|
await invalidateCache(`kv_roomlist_${ctx.session.user.id}`);
|
||||||
|
|
||||||
await publishToChannel(
|
await publishToChannel(
|
||||||
`${ctx.session.user.id}`,
|
`${ctx.session.user.id}`,
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { createTRPCRouter, protectedProcedure } from "~/server/api/trpc";
|
import { createTRPCRouter, protectedProcedure } from "~/server/api/trpc";
|
||||||
import { env } from "~/env.mjs";
|
import { env } from "~/env.mjs";
|
||||||
import { redis } from "~/server/redis";
|
import { invalidateCache } from "~/server/redis";
|
||||||
|
|
||||||
export const sessionRouter = createTRPCRouter({
|
export const sessionRouter = createTRPCRouter({
|
||||||
deleteAllByUserId: protectedProcedure
|
deleteAllByUserId: protectedProcedure
|
||||||
|
@ -18,7 +18,7 @@ export const sessionRouter = createTRPCRouter({
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!!sessions) {
|
if (!!sessions) {
|
||||||
await redis.del(`${env.APP_ENV}_kv_userlist_admin`);
|
await invalidateCache(`kv_userlist_admin`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return !!sessions;
|
return !!sessions;
|
||||||
|
@ -27,7 +27,7 @@ export const sessionRouter = createTRPCRouter({
|
||||||
const sessions = await ctx.prisma.session.deleteMany();
|
const sessions = await ctx.prisma.session.deleteMany();
|
||||||
|
|
||||||
if (!!sessions) {
|
if (!!sessions) {
|
||||||
await redis.del(`${env.APP_ENV}_kv_userlist_admin`);
|
await invalidateCache(`kv_userlist_admin`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return !!sessions;
|
return !!sessions;
|
||||||
|
|
|
@ -6,24 +6,20 @@ import type { Role } from "~/utils/types";
|
||||||
import { Resend } from "resend";
|
import { Resend } from "resend";
|
||||||
import { Goodbye } from "~/components/templates/Goodbye";
|
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);
|
const resend = new Resend(process.env.RESEND_API_KEY);
|
||||||
|
|
||||||
export const userRouter = createTRPCRouter({
|
export const userRouter = createTRPCRouter({
|
||||||
countAll: protectedProcedure.query(async ({ ctx }) => {
|
countAll: protectedProcedure.query(async ({ ctx }) => {
|
||||||
const cachedResult = await redis.get<number>(
|
const cachedResult = await fetchCache<number>(`kv_usercount_admin`);
|
||||||
`${env.APP_ENV}_kv_usercount_admin`
|
|
||||||
);
|
|
||||||
|
|
||||||
if (cachedResult) {
|
if (cachedResult) {
|
||||||
return cachedResult;
|
return cachedResult;
|
||||||
} else {
|
} else {
|
||||||
const usersCount = await ctx.prisma.user.count();
|
const usersCount = await ctx.prisma.user.count();
|
||||||
|
|
||||||
await redis.set(`${env.APP_ENV}_kv_usercount_admin`, usersCount, {
|
await setCache(`kv_usercount_admin`, usersCount);
|
||||||
ex: Number(env.UPSTASH_REDIS_EXPIRY_SECONDS),
|
|
||||||
});
|
|
||||||
|
|
||||||
return usersCount;
|
return usersCount;
|
||||||
}
|
}
|
||||||
|
@ -48,7 +44,7 @@ export const userRouter = createTRPCRouter({
|
||||||
});
|
});
|
||||||
}),
|
}),
|
||||||
getAll: protectedProcedure.query(async ({ ctx }) => {
|
getAll: protectedProcedure.query(async ({ ctx }) => {
|
||||||
const cachedResult = await redis.get<
|
const cachedResult = await fetchCache<
|
||||||
{
|
{
|
||||||
accounts: {
|
accounts: {
|
||||||
provider: string;
|
provider: string;
|
||||||
|
@ -62,7 +58,7 @@ export const userRouter = createTRPCRouter({
|
||||||
name: string | null;
|
name: string | null;
|
||||||
email: string | null;
|
email: string | null;
|
||||||
}[]
|
}[]
|
||||||
>(`${env.APP_ENV}_kv_userlist_admin`);
|
>(`kv_userlist_admin`);
|
||||||
|
|
||||||
if (cachedResult) {
|
if (cachedResult) {
|
||||||
return cachedResult.map((user) => {
|
return cachedResult.map((user) => {
|
||||||
|
@ -92,9 +88,7 @@ export const userRouter = createTRPCRouter({
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
await redis.set(`${env.APP_ENV}_kv_userlist_admin`, users, {
|
await setCache(`${env.APP_ENV}_kv_userlist_admin`, users);
|
||||||
ex: Number(env.UPSTASH_REDIS_EXPIRY_SECONDS),
|
|
||||||
});
|
|
||||||
|
|
||||||
return users;
|
return users;
|
||||||
}
|
}
|
||||||
|
@ -132,8 +126,8 @@ export const userRouter = createTRPCRouter({
|
||||||
react: Goodbye({ name: user.name }),
|
react: Goodbye({ name: user.name }),
|
||||||
});
|
});
|
||||||
|
|
||||||
await redis.del(`${env.APP_ENV}_kv_usercount_admin`);
|
await invalidateCache(`kv_usercount_admin`);
|
||||||
await redis.del(`${env.APP_ENV}_kv_userlist_admin`);
|
await invalidateCache(`kv_userlist_admin`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return !!user;
|
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;
|
return !!user;
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -4,22 +4,18 @@ import { publishToChannel } from "~/server/ably";
|
||||||
import { createTRPCRouter, protectedProcedure } from "~/server/api/trpc";
|
import { createTRPCRouter, protectedProcedure } from "~/server/api/trpc";
|
||||||
import { env } from "~/env.mjs";
|
import { env } from "~/env.mjs";
|
||||||
import type { Room } from "@prisma/client";
|
import type { Room } from "@prisma/client";
|
||||||
import { redis } from "~/server/redis";
|
import { fetchCache, invalidateCache, setCache } from "~/server/redis";
|
||||||
|
|
||||||
export const voteRouter = createTRPCRouter({
|
export const voteRouter = createTRPCRouter({
|
||||||
countAll: protectedProcedure.query(async ({ ctx }) => {
|
countAll: protectedProcedure.query(async ({ ctx }) => {
|
||||||
const cachedResult = await redis.get<number>(
|
const cachedResult = await fetchCache<number>(`kv_votecount_admin`);
|
||||||
`${env.APP_ENV}_kv_votecount_admin`
|
|
||||||
);
|
|
||||||
|
|
||||||
if (cachedResult) {
|
if (cachedResult) {
|
||||||
return cachedResult;
|
return cachedResult;
|
||||||
} else {
|
} else {
|
||||||
const votesCount = await ctx.prisma.vote.count();
|
const votesCount = await ctx.prisma.vote.count();
|
||||||
|
|
||||||
await redis.set(`${env.APP_ENV}_kv_votecount_admin`, votesCount, {
|
await setCache(`kv_votecount_admin`, votesCount);
|
||||||
ex: Number(env.UPSTASH_REDIS_EXPIRY_SECONDS),
|
|
||||||
});
|
|
||||||
|
|
||||||
return votesCount;
|
return votesCount;
|
||||||
}
|
}
|
||||||
|
@ -27,7 +23,7 @@ export const voteRouter = createTRPCRouter({
|
||||||
getAllByRoomId: protectedProcedure
|
getAllByRoomId: protectedProcedure
|
||||||
.input(z.object({ roomId: z.string() }))
|
.input(z.object({ roomId: z.string() }))
|
||||||
.query(async ({ ctx, input }) => {
|
.query(async ({ ctx, input }) => {
|
||||||
const cachedResult = await redis.get<
|
const cachedResult = await fetchCache<
|
||||||
{
|
{
|
||||||
value: string;
|
value: string;
|
||||||
room: Room;
|
room: Room;
|
||||||
|
@ -39,7 +35,7 @@ export const voteRouter = createTRPCRouter({
|
||||||
};
|
};
|
||||||
roomId: string;
|
roomId: string;
|
||||||
}[]
|
}[]
|
||||||
>(`${env.APP_ENV}_kv_votes_${input.roomId}`);
|
>(`kv_votes_${input.roomId}`);
|
||||||
|
|
||||||
if (cachedResult) {
|
if (cachedResult) {
|
||||||
return cachedResult;
|
return cachedResult;
|
||||||
|
@ -63,11 +59,7 @@ export const voteRouter = createTRPCRouter({
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
await redis.set(
|
await setCache(`kv_votes_${input.roomId}`, votesByRoomId);
|
||||||
`${env.APP_ENV}_kv_votes_${input.roomId}`,
|
|
||||||
votesByRoomId,
|
|
||||||
{ ex: Number(env.UPSTASH_REDIS_EXPIRY_SECONDS) }
|
|
||||||
);
|
|
||||||
|
|
||||||
return votesByRoomId;
|
return votesByRoomId;
|
||||||
}
|
}
|
||||||
|
@ -106,8 +98,8 @@ export const voteRouter = createTRPCRouter({
|
||||||
});
|
});
|
||||||
|
|
||||||
if (vote) {
|
if (vote) {
|
||||||
await redis.del(`${env.APP_ENV}_kv_votecount_admin`);
|
await invalidateCache(`kv_votecount_admin`);
|
||||||
await redis.del(`${env.APP_ENV}_kv_votes_${input.roomId}`);
|
await invalidateCache(`kv_votes_${input.roomId}`);
|
||||||
|
|
||||||
await publishToChannel(`${vote.roomId}`, "VOTE_UPDATE", "UPDATE");
|
await publishToChannel(`${vote.roomId}`, "VOTE_UPDATE", "UPDATE");
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,9 +19,10 @@ import { type Session } from "next-auth";
|
||||||
|
|
||||||
import { getServerAuthSession } from "~/server/auth";
|
import { getServerAuthSession } from "~/server/auth";
|
||||||
import { prisma } from "~/server/db";
|
import { prisma } from "~/server/db";
|
||||||
|
import { Redis } from "@upstash/redis";
|
||||||
|
|
||||||
const rateLimit = new Ratelimit({
|
const rateLimit = new Ratelimit({
|
||||||
redis,
|
redis: Redis.fromEnv(),
|
||||||
limiter: Ratelimit.slidingWindow(
|
limiter: Ratelimit.slidingWindow(
|
||||||
Number(env.UPSTASH_RATELIMIT_REQUESTS),
|
Number(env.UPSTASH_RATELIMIT_REQUESTS),
|
||||||
`${Number(env.UPSTASH_RATELIMIT_SECONDS)}s`
|
`${Number(env.UPSTASH_RATELIMIT_SECONDS)}s`
|
||||||
|
@ -75,7 +76,6 @@ export const createTRPCContext = async (opts: CreateNextContextOptions) => {
|
||||||
import { initTRPC, TRPCError } from "@trpc/server";
|
import { initTRPC, TRPCError } from "@trpc/server";
|
||||||
import superjson from "superjson";
|
import superjson from "superjson";
|
||||||
import { Ratelimit } from "@upstash/ratelimit";
|
import { Ratelimit } from "@upstash/ratelimit";
|
||||||
import { redis } from "../redis";
|
|
||||||
import { env } from "~/env.mjs";
|
import { env } from "~/env.mjs";
|
||||||
|
|
||||||
const t = initTRPC.context<typeof createTRPCContext>().create({
|
const t = initTRPC.context<typeof createTRPCContext>().create({
|
||||||
|
|
|
@ -12,7 +12,7 @@ import { prisma } from "~/server/db";
|
||||||
import type { Role } from "~/utils/types";
|
import type { Role } from "~/utils/types";
|
||||||
import { Resend } from "resend";
|
import { Resend } from "resend";
|
||||||
import { Welcome } from "../components/templates/Welcome";
|
import { Welcome } from "../components/templates/Welcome";
|
||||||
import { redis } from "./redis";
|
import { invalidateCache } from "./redis";
|
||||||
|
|
||||||
const resend = new Resend(process.env.RESEND_API_KEY);
|
const resend = new Resend(process.env.RESEND_API_KEY);
|
||||||
|
|
||||||
|
@ -61,15 +61,15 @@ export const authOptions: NextAuthOptions = {
|
||||||
|
|
||||||
react: Welcome({ name: user.name }),
|
react: Welcome({ name: user.name }),
|
||||||
});
|
});
|
||||||
await redis.del(`${env.APP_ENV}_kv_userlist_admin`);
|
await invalidateCache(`kv_userlist_admin`);
|
||||||
await redis.del(`${env.APP_ENV}_kv_usercount_admin`);
|
await invalidateCache(`kv_usercount_admin`);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async signIn({}) {
|
async signIn({}) {
|
||||||
await redis.del(`${env.APP_ENV}_kv_userlist_admin`);
|
await invalidateCache(`kv_userlist_admin`);
|
||||||
},
|
},
|
||||||
async signOut() {
|
async signOut() {
|
||||||
await redis.del(`${env.APP_ENV}_kv_userlist_admin`);
|
await invalidateCache(`kv_userlist_admin`);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
// @ts-ignore This adapter should work...
|
// @ts-ignore This adapter should work...
|
||||||
|
|
|
@ -1,6 +1,42 @@
|
||||||
import { Redis } from "@upstash/redis";
|
import { Redis } from "@upstash/redis";
|
||||||
import https from "https";
|
import https from "https";
|
||||||
|
import { env } from "~/env.mjs";
|
||||||
|
|
||||||
export const redis = Redis.fromEnv({
|
export const redis = Redis.fromEnv({
|
||||||
agent: new https.Agent({ keepAlive: true }),
|
agent: new https.Agent({ keepAlive: true }),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const setCache = async <T>(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 <T>(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;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
Loading…
Add table
Reference in a new issue