Lets try ioredis

This commit is contained in:
Atridad Lahiji 2023-11-21 09:05:09 -07:00
parent 4341c2e7cc
commit 5e57e2b416
No known key found for this signature in database
9 changed files with 90 additions and 103 deletions

View file

@ -3,11 +3,8 @@ DATABASE_URL=""
DATABASE_AUTH_TOKEN=""
# Redis
UPSTASH_REDIS_REST_URL=""
UPSTASH_REDIS_REST_TOKEN=""
UPSTASH_REDIS_EXPIRY_SECONDS=""
UPSTASH_RATELIMIT_REQUESTS=""
UPSTASH_RATELIMIT_SECONDS=""
REDIS_URL=""
REDIS_EXPIRY_SECONDS=""
#Auth
NEXT_PUBLIC_CLERK_SIGN_UP_URL="/sign-up"

View file

@ -48,10 +48,7 @@ const Navbar = ({ title }: NavbarProps) => {
width={32}
height={32}
/>
<span className="hidden md:inline-flex">
{title}
{env.NEXT_PUBLIC_APP_ENV === "development" && " >> Staging"}
</span>
<span className="hidden md:inline-flex">{title}</span>
</Link>
</div>

View file

@ -1,13 +1,12 @@
import { Redis } from "@upstash/redis";
import { Redis } from "ioredis";
import { env } from "env.mjs";
export const redis = Redis.fromEnv();
export const redis = env.REDIS_URL ? new Redis(env.REDIS_URL) : null;
export const setCache = async <T>(key: string, value: T) => {
console.log(env.REDIS_URL);
try {
await redis.set(`${env.APP_ENV}_${key}`, value, {
ex: Number(env.UPSTASH_REDIS_EXPIRY_SECONDS),
});
await redis?.set(`${env.APP_ENV}_${key}`, JSON.stringify(value));
return true;
} catch {
return false;
@ -16,8 +15,8 @@ export const setCache = async <T>(key: string, value: T) => {
export const fetchCache = async <T>(key: string) => {
try {
const result = await redis.get(`${env.APP_ENV}_${key}`);
return result as T;
const result = (await redis?.get(`${env.APP_ENV}_${key}`)) as string;
return JSON.parse(result) as T;
} catch {
return null;
}
@ -25,7 +24,7 @@ export const fetchCache = async <T>(key: string) => {
export const invalidateCache = async (key: string) => {
try {
await redis.del(`${env.APP_ENV}_${key}`);
await redis?.del(`${env.APP_ENV}_${key}`);
return true;
} catch {
return false;

View file

@ -8,6 +8,7 @@ import { EventTypes } from "@/_utils/types";
import { getAuth } from "@clerk/nextjs/server";
import { createId } from "@paralleldrive/cuid2";
import { eq } from "drizzle-orm";
import { env } from "env.mjs";
export async function GET(
request: Request,
@ -61,6 +62,7 @@ export async function DELETE(
const success = deletedRoom.length > 0;
if (success) {
if (env.APP_ENV === "production")
await invalidateCache(`kv_roomlist_${userId}`);
await publishToMultipleChannels(

View file

@ -8,17 +8,21 @@ import { createId } from "@paralleldrive/cuid2";
import { publishToChannel } from "@/_lib/ably";
import { EventTypes } from "@/_utils/types";
import { getAuth } from "@clerk/nextjs/server";
import { env } from "env.mjs";
export async function GET(request: Request) {
const { userId } = getAuth(request as NextRequest);
const cachedResult = await fetchCache<
const cachedResult =
env.APP_ENV === "production"
? await fetchCache<
{
id: string;
createdAt: Date;
roomName: string;
}[]
>(`kv_roomlist_${userId}`);
>(`kv_roomlist_${userId}`)
: null;
if (cachedResult) {
return NextResponse.json(cachedResult, {
@ -30,6 +34,7 @@ export async function GET(request: Request) {
where: eq(rooms.userId, userId || ""),
});
if (env.APP_ENV === "production")
await setCache(`kv_roomlist_${userId}`, roomList);
return NextResponse.json(roomList, {
@ -60,6 +65,7 @@ export async function POST(request: Request) {
const success = room.length > 0;
if (room) {
if (env.APP_ENV === "production")
await invalidateCache(`kv_roomlist_${userId}`);
await publishToChannel(

View file

@ -5,11 +5,8 @@ export const env = createEnv({
server: {
DATABASE_URL: z.string().url(),
DATABASE_AUTH_TOKEN: z.string(),
UPSTASH_REDIS_REST_URL: z.string().url(),
UPSTASH_REDIS_REST_TOKEN: z.string(),
UPSTASH_REDIS_EXPIRY_SECONDS: z.string(),
UPSTASH_RATELIMIT_REQUESTS: z.string(),
UPSTASH_RATELIMIT_SECONDS: z.string(),
REDIS_URL: z.string().url().optional(),
REDIS_EXPIRY_SECONDS: z.string().optional(),
ABLY_API_KEY: z.string(),
APP_ENV: z.string(),
UNKEY_ROOT_KEY: z.string(),

View file

@ -1,21 +1,9 @@
import { authMiddleware, redirectToSignIn } from "@clerk/nextjs";
import { validateRequest } from "./app/_lib/unkey";
import { NextResponse } from "next/server";
import { Ratelimit } from "@upstash/ratelimit";
import { Redis } from "@upstash/redis";
import { env } from "./env.mjs";
const shitList = ["ama.ab.ca"];
const rateLimit = new Ratelimit({
redis: Redis.fromEnv(),
limiter: Ratelimit.slidingWindow(
Number(env.UPSTASH_RATELIMIT_REQUESTS),
`${Number(env.UPSTASH_RATELIMIT_SECONDS)}s`
),
analytics: true,
});
export default authMiddleware({
ignoredRoutes: ["/"],
publicRoutes: [
@ -25,15 +13,8 @@ export default authMiddleware({
],
afterAuth: async (auth, req) => {
if (!auth.userId && auth.isPublicRoute) {
const { success } = await rateLimit.limit(req.ip || "");
if (success) {
return NextResponse.next();
}
return new NextResponse("TOO MANY REQUESTS", {
status: 429,
statusText: "Too many requests!",
});
}
if (auth.userId) {
const email = auth.sessionClaims.email as string;
@ -54,15 +35,6 @@ export default authMiddleware({
}
if (req.nextUrl.pathname.includes("/api/internal")) {
const { success } = await rateLimit.limit(req.ip || "");
if (!success) {
return new NextResponse("TOO MANY REQUESTS", {
status: 429,
statusText: "Too many requests!",
});
}
if (auth.userId) {
return NextResponse.next();
} else {
@ -74,15 +46,6 @@ export default authMiddleware({
}
if (req.nextUrl.pathname.includes("/api/external/private")) {
const { success } = await rateLimit.limit(req.ip || "");
if (!success) {
return new NextResponse("TOO MANY REQUESTS", {
status: 429,
statusText: "Too many requests!",
});
}
const isValid = await validateRequest(req);
if (isValid) {

View file

@ -21,14 +21,13 @@
"@t3-oss/env-nextjs": "0.7.1",
"@tanstack/react-query": "5.8.4",
"@unkey/api": "0.12.0",
"@upstash/ratelimit": "0.4.4",
"@upstash/redis": "1.25.1",
"@vercel/analytics": "1.1.1",
"ably": "1.2.47",
"autoprefixer": "10.4.16",
"csv42": "5.0.0",
"dotenv": "16.3.1",
"drizzle-orm": "0.29.0",
"ioredis": "^5.3.2",
"next": "14.0.1",
"nextjs-cors": "2.1.2",
"postcss": "8.4.31",

89
pnpm-lock.yaml generated
View file

@ -26,12 +26,6 @@ dependencies:
'@unkey/api':
specifier: 0.12.0
version: 0.12.0
'@upstash/ratelimit':
specifier: 0.4.4
version: 0.4.4
'@upstash/redis':
specifier: 1.25.1
version: 1.25.1
'@vercel/analytics':
specifier: 1.1.1
version: 1.1.1
@ -50,6 +44,9 @@ dependencies:
drizzle-orm:
specifier: 0.29.0
version: 0.29.0(@libsql/client@0.4.0-pre.1)(better-sqlite3@9.1.1)
ioredis:
specifier: ^5.3.2
version: 5.3.2
next:
specifier: 14.0.1
version: 14.0.1(react-dom@18.2.0)(react@18.2.0)
@ -800,6 +797,10 @@ packages:
resolution: {integrity: sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==}
dev: true
/@ioredis/commands@1.2.0:
resolution: {integrity: sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg==}
dev: false
/@jridgewell/gen-mapping@0.3.3:
resolution: {integrity: sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==}
engines: {node: '>=6.0.0'}
@ -1548,25 +1549,6 @@ packages:
resolution: {integrity: sha512-BT2I52rwTQ1j8S9aX9tKH3P3Efvtvgu8dD8pExYvKXG9uWPditNOwO6t8aeXLGCWdyzTqxmueBeR0uD0DN5U7A==}
dev: false
/@upstash/core-analytics@0.0.6:
resolution: {integrity: sha512-cpPSR0XJAJs4Ddz9nq3tINlPS5aLfWVCqhhtHnXt4p7qr5+/Znlt1Es736poB/9rnl1hAHrOsOvVj46NEXcVqA==}
engines: {node: '>=16.0.0'}
dependencies:
'@upstash/redis': 1.25.1
dev: false
/@upstash/ratelimit@0.4.4:
resolution: {integrity: sha512-y3q6cNDdcRQ2MRPRf5UNWBN36IwnZ4kAEkGoH3i6OqdWwz4qlBxNsw4/Rpqn9h93+Nx1cqg5IOq7O2e2zMJY1w==}
dependencies:
'@upstash/core-analytics': 0.0.6
dev: false
/@upstash/redis@1.25.1:
resolution: {integrity: sha512-ACj0GhJ4qrQyBshwFgPod6XufVEfKX2wcaihsEvSdLYnY+m+pa13kGt1RXm/yTHKf4TQi/Dy2A8z/y6WUEOmlg==}
dependencies:
crypto-js: 4.2.0
dev: false
/@vercel/analytics@1.1.1:
resolution: {integrity: sha512-+NqgNmSabg3IFfxYhrWCfB/H+RCUOCR5ExRudNG2+pcRehq628DJB5e1u1xqwpLtn4pAYii4D98w7kofORAGQA==}
dependencies:
@ -2031,6 +2013,11 @@ packages:
mimic-response: 1.0.1
dev: false
/cluster-key-slot@1.1.2:
resolution: {integrity: sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==}
engines: {node: '>=0.10.0'}
dev: false
/color-convert@2.0.1:
resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
engines: {node: '>=7.0.0'}
@ -2097,10 +2084,6 @@ packages:
which: 2.0.2
dev: true
/crypto-js@4.2.0:
resolution: {integrity: sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==}
dev: false
/css-selector-tokenizer@0.8.0:
resolution: {integrity: sha512-Jd6Ig3/pe62/qe5SBPTN8h8LeUg/pT4lLgtavPf7updwwHpvFzxvOQBHYj2LZDMjUnBzgvIUSjRcf6oT5HzHFg==}
dependencies:
@ -2184,7 +2167,6 @@ packages:
optional: true
dependencies:
ms: 2.1.2
dev: true
/decompress-response@6.0.0:
resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==}
@ -2233,6 +2215,11 @@ packages:
engines: {node: '>=0.4.0'}
dev: false
/denque@2.1.0:
resolution: {integrity: sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==}
engines: {node: '>=0.10'}
dev: false
/dequal@2.0.3:
resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==}
engines: {node: '>=6'}
@ -3371,6 +3358,23 @@ packages:
side-channel: 1.0.4
dev: true
/ioredis@5.3.2:
resolution: {integrity: sha512-1DKMMzlIHM02eBBVOFQ1+AolGjs6+xEcM4PDL7NqOS6szq7H9jSaEkIUH6/a5Hl241LzW6JLSiAbNvTQjUupUA==}
engines: {node: '>=12.22.0'}
dependencies:
'@ioredis/commands': 1.2.0
cluster-key-slot: 1.1.2
debug: 4.3.4
denque: 2.1.0
lodash.defaults: 4.2.0
lodash.isarguments: 3.1.0
redis-errors: 1.2.0
redis-parser: 3.0.0
standard-as-callback: 2.1.0
transitivePeerDependencies:
- supports-color
dev: false
/is-array-buffer@3.0.2:
resolution: {integrity: sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==}
dependencies:
@ -3692,6 +3696,14 @@ packages:
p-locate: 5.0.0
dev: true
/lodash.defaults@4.2.0:
resolution: {integrity: sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==}
dev: false
/lodash.isarguments@3.1.0:
resolution: {integrity: sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==}
dev: false
/lodash.merge@4.6.2:
resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
dev: true
@ -3844,7 +3856,6 @@ packages:
/ms@2.1.2:
resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==}
dev: true
/ms@2.1.3:
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
@ -4363,6 +4374,18 @@ packages:
picomatch: 2.3.1
dev: true
/redis-errors@1.2.0:
resolution: {integrity: sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==}
engines: {node: '>=4'}
dev: false
/redis-parser@3.0.0:
resolution: {integrity: sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==}
engines: {node: '>=4'}
dependencies:
redis-errors: 1.2.0
dev: false
/reflect.getprototypeof@1.0.4:
resolution: {integrity: sha512-ECkTw8TmJwW60lOTR+ZkODISW6RQ8+2CL3COqtiJKLd6MmB45hN51HprHFziKLGkAuTGQhBb91V8cy+KHlaCjw==}
engines: {node: '>= 0.4'}
@ -4664,6 +4687,10 @@ packages:
get-source: 2.0.12
dev: true
/standard-as-callback@2.1.0:
resolution: {integrity: sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==}
dev: false
/stoppable@1.1.0:
resolution: {integrity: sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw==}
engines: {node: '>=4', npm: '>=6'}