feat: 房间 24 小时自动过期,添加 TTL 清理机制
This commit is contained in:
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
Warnings:
|
||||
|
||||
- Added the required column `expiresAt` to the `Room` table without a default value. This is not possible if the table is not empty.
|
||||
|
||||
*/
|
||||
-- RedefineTables
|
||||
PRAGMA defer_foreign_keys=ON;
|
||||
PRAGMA foreign_keys=OFF;
|
||||
CREATE TABLE "new_Room" (
|
||||
"id" TEXT NOT NULL PRIMARY KEY,
|
||||
"data" TEXT NOT NULL,
|
||||
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"expiresAt" DATETIME NOT NULL
|
||||
);
|
||||
INSERT INTO "new_Room" ("createdAt", "data", "id", "expiresAt") SELECT "createdAt", "data", "id", "createdAt" FROM "Room";
|
||||
DROP TABLE "Room";
|
||||
ALTER TABLE "new_Room" RENAME TO "Room";
|
||||
PRAGMA foreign_keys=ON;
|
||||
PRAGMA defer_foreign_keys=OFF;
|
||||
@@ -11,4 +11,5 @@ model Room {
|
||||
id String @id
|
||||
data String
|
||||
createdAt DateTime @default(now())
|
||||
expiresAt DateTime
|
||||
}
|
||||
|
||||
+31
-2
@@ -1,6 +1,8 @@
|
||||
import { prisma } from "./prisma";
|
||||
import { Restaurant } from "@/types";
|
||||
|
||||
const ROOM_TTL_MS = 24 * 60 * 60 * 1000; // 24 hours
|
||||
|
||||
export interface RoomData {
|
||||
users: string[];
|
||||
restaurants: Restaurant[];
|
||||
@@ -23,7 +25,29 @@ function normalize(raw: Partial<RoomData>): RoomData {
|
||||
};
|
||||
}
|
||||
|
||||
let lastCleanup = 0;
|
||||
const CLEANUP_INTERVAL_MS = 60 * 60 * 1000; // at most once per hour
|
||||
|
||||
async function cleanupExpiredRooms() {
|
||||
const now = Date.now();
|
||||
if (now - lastCleanup < CLEANUP_INTERVAL_MS) return;
|
||||
lastCleanup = now;
|
||||
|
||||
try {
|
||||
const { count } = await prisma.room.deleteMany({
|
||||
where: { expiresAt: { lt: new Date() } },
|
||||
});
|
||||
if (count > 0) {
|
||||
console.log(`Cleaned up ${count} expired room(s)`);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("Room cleanup failed:", e);
|
||||
}
|
||||
}
|
||||
|
||||
export async function createRoom(restaurants: Restaurant[]): Promise<string> {
|
||||
await cleanupExpiredRooms();
|
||||
|
||||
const data: RoomData = {
|
||||
users: [],
|
||||
restaurants,
|
||||
@@ -32,6 +56,7 @@ export async function createRoom(restaurants: Restaurant[]): Promise<string> {
|
||||
match: null,
|
||||
};
|
||||
|
||||
const expiresAt = new Date(Date.now() + ROOM_TTL_MS);
|
||||
let roomId: string;
|
||||
let attempts = 0;
|
||||
|
||||
@@ -40,7 +65,7 @@ export async function createRoom(restaurants: Restaurant[]): Promise<string> {
|
||||
const existing = await prisma.room.findUnique({ where: { id: roomId } });
|
||||
if (!existing) {
|
||||
await prisma.room.create({
|
||||
data: { id: roomId, data: JSON.stringify(data) },
|
||||
data: { id: roomId, data: JSON.stringify(data), expiresAt },
|
||||
});
|
||||
return roomId;
|
||||
}
|
||||
@@ -49,7 +74,7 @@ export async function createRoom(restaurants: Restaurant[]): Promise<string> {
|
||||
|
||||
roomId = generateRoomId() + String(Date.now()).slice(-2);
|
||||
await prisma.room.create({
|
||||
data: { id: roomId, data: JSON.stringify(data) },
|
||||
data: { id: roomId, data: JSON.stringify(data), expiresAt },
|
||||
});
|
||||
return roomId;
|
||||
}
|
||||
@@ -59,6 +84,10 @@ export async function getRoomData(
|
||||
): Promise<RoomData | null> {
|
||||
const room = await prisma.room.findUnique({ where: { id: roomId } });
|
||||
if (!room) return null;
|
||||
if (room.expiresAt < new Date()) {
|
||||
prisma.room.delete({ where: { id: roomId } }).catch(() => {});
|
||||
return null;
|
||||
}
|
||||
return normalize(JSON.parse(room.data));
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user