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
|
id String @id
|
||||||
data String
|
data String
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
|
expiresAt DateTime
|
||||||
}
|
}
|
||||||
|
|||||||
+31
-2
@@ -1,6 +1,8 @@
|
|||||||
import { prisma } from "./prisma";
|
import { prisma } from "./prisma";
|
||||||
import { Restaurant } from "@/types";
|
import { Restaurant } from "@/types";
|
||||||
|
|
||||||
|
const ROOM_TTL_MS = 24 * 60 * 60 * 1000; // 24 hours
|
||||||
|
|
||||||
export interface RoomData {
|
export interface RoomData {
|
||||||
users: string[];
|
users: string[];
|
||||||
restaurants: Restaurant[];
|
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> {
|
export async function createRoom(restaurants: Restaurant[]): Promise<string> {
|
||||||
|
await cleanupExpiredRooms();
|
||||||
|
|
||||||
const data: RoomData = {
|
const data: RoomData = {
|
||||||
users: [],
|
users: [],
|
||||||
restaurants,
|
restaurants,
|
||||||
@@ -32,6 +56,7 @@ export async function createRoom(restaurants: Restaurant[]): Promise<string> {
|
|||||||
match: null,
|
match: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const expiresAt = new Date(Date.now() + ROOM_TTL_MS);
|
||||||
let roomId: string;
|
let roomId: string;
|
||||||
let attempts = 0;
|
let attempts = 0;
|
||||||
|
|
||||||
@@ -40,7 +65,7 @@ export async function createRoom(restaurants: Restaurant[]): Promise<string> {
|
|||||||
const existing = await prisma.room.findUnique({ where: { id: roomId } });
|
const existing = await prisma.room.findUnique({ where: { id: roomId } });
|
||||||
if (!existing) {
|
if (!existing) {
|
||||||
await prisma.room.create({
|
await prisma.room.create({
|
||||||
data: { id: roomId, data: JSON.stringify(data) },
|
data: { id: roomId, data: JSON.stringify(data), expiresAt },
|
||||||
});
|
});
|
||||||
return roomId;
|
return roomId;
|
||||||
}
|
}
|
||||||
@@ -49,7 +74,7 @@ export async function createRoom(restaurants: Restaurant[]): Promise<string> {
|
|||||||
|
|
||||||
roomId = generateRoomId() + String(Date.now()).slice(-2);
|
roomId = generateRoomId() + String(Date.now()).slice(-2);
|
||||||
await prisma.room.create({
|
await prisma.room.create({
|
||||||
data: { id: roomId, data: JSON.stringify(data) },
|
data: { id: roomId, data: JSON.stringify(data), expiresAt },
|
||||||
});
|
});
|
||||||
return roomId;
|
return roomId;
|
||||||
}
|
}
|
||||||
@@ -59,6 +84,10 @@ export async function getRoomData(
|
|||||||
): Promise<RoomData | null> {
|
): Promise<RoomData | null> {
|
||||||
const room = await prisma.room.findUnique({ where: { id: roomId } });
|
const room = await prisma.room.findUnique({ where: { id: roomId } });
|
||||||
if (!room) return null;
|
if (!room) return null;
|
||||||
|
if (room.expiresAt < new Date()) {
|
||||||
|
prisma.room.delete({ where: { id: roomId } }).catch(() => {});
|
||||||
|
return null;
|
||||||
|
}
|
||||||
return normalize(JSON.parse(room.data));
|
return normalize(JSON.parse(room.data));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user