import { prisma } from "@/lib/db"; const cancelledIds = new Set(); export class JobCancelledError extends Error { constructor(message = "任務已停止") { super(message); this.name = "JobCancelledError"; } } export function markJobCancelledLocal(jobId: string) { cancelledIds.add(jobId); } export function clearJobCancelledLocal(jobId: string) { cancelledIds.delete(jobId); } export async function isJobCancelled(jobId: string): Promise { if (cancelledIds.has(jobId)) return true; const job = await prisma.backgroundJob.findUnique({ where: { id: jobId }, select: { status: true }, }); return job?.status === "cancelled"; } export async function assertJobNotCancelled(jobId?: string) { if (!jobId) return; if (await isJobCancelled(jobId)) { throw new JobCancelledError(); } } export async function cancelJob(jobId: string): Promise<{ ok: boolean; error?: string }> { const job = await prisma.backgroundJob.findUnique({ where: { id: jobId } }); if (!job) return { ok: false, error: "找不到任務" }; if (job.status === "completed") return { ok: false, error: "任務已完成" }; if (job.status === "failed") return { ok: false, error: "任務已失敗" }; if (job.status === "cancelled") return { ok: true }; markJobCancelledLocal(jobId); await prisma.backgroundJob.update({ where: { id: jobId }, data: { status: "cancelled", progress: "已停止", completedAt: new Date(), }, }); return { ok: true }; }