55 lines
1.5 KiB
TypeScript
55 lines
1.5 KiB
TypeScript
import { prisma } from "@/lib/db";
|
|
|
|
const cancelledIds = new Set<string>();
|
|
|
|
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<boolean> {
|
|
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 };
|
|
}
|