haixunMaster/app/api/jobs/route.ts

65 lines
2.2 KiB
TypeScript

import { NextResponse } from "next/server";
import { prisma } from "@/lib/db";
import { authErrorResponse } from "@/lib/auth/api";
import { requireSessionUser } from "@/lib/auth/session";
import { recoverStaleBackgroundJobs } from "@/lib/jobs/runner";
export async function GET(request: Request) {
try {
const user = await requireSessionUser();
const { searchParams } = new URL(request.url);
const activeOnly = searchParams.get("active") === "1";
const topicId = searchParams.get("topicId");
const limit = Math.min(parseInt(searchParams.get("limit") ?? "10", 10), 30);
const userAccounts = await prisma.account.findMany({
where: { userId: user.id },
select: { id: true },
});
const accountIds = userAccounts.map((account) => account.id);
if (accountIds.length === 0) {
return NextResponse.json({ jobs: [] });
}
if (activeOnly) {
await recoverStaleBackgroundJobs();
}
const baseWhere = {
accountId: { in: accountIds },
...(topicId ? { topicId } : {}),
};
const jobs = activeOnly
? await prisma.backgroundJob.findMany({
where: { ...baseWhere, status: { in: ["pending", "running"] } },
orderBy: { createdAt: "desc" },
})
: await Promise.all([
prisma.backgroundJob.findMany({
where: { ...baseWhere, status: { in: ["pending", "running"] } },
orderBy: { createdAt: "desc" },
}),
prisma.backgroundJob.findMany({
where: baseWhere,
orderBy: { createdAt: "desc" },
take: limit,
}),
]).then(([active, recent]) => {
const merged = new Map([...active, ...recent].map((job) => [job.id, job]));
return [...merged.values()].sort(
(a, b) => b.createdAt.getTime() - a.createdAt.getTime()
);
});
return NextResponse.json({ jobs });
} catch (error) {
const authRes = authErrorResponse(error);
if (authRes) return authRes;
console.error("[jobs GET]", error);
return NextResponse.json(
{ error: error instanceof Error ? error.message : "載入任務失敗", jobs: [] },
{ status: 500 }
);
}
}