68 lines
2.0 KiB
TypeScript
68 lines
2.0 KiB
TypeScript
import { prisma } from "@/lib/prisma";
|
|
|
|
/**
|
|
* Wrapper untuk cron route handler — otomatis log start/finish/error ke
|
|
* `CronRun`. Idempotent terhadap kegagalan: kalau row gagal dibuat (DB down),
|
|
* fn tetap jalan dan kegagalannya hanya hilang log.
|
|
*
|
|
* Pemakaian:
|
|
* ```ts
|
|
* return runCron("auto-complete-trips", async () => {
|
|
* const result = await tripService.autoCompletePastTrips();
|
|
* return { completed: result.count, ids: result.ids };
|
|
* });
|
|
* ```
|
|
*
|
|
* Caller bertanggung jawab untuk mengembalikan NextResponse — `runCron`
|
|
* cuma menjalankan fn dan log; return value fn dipassthrough sebagai `payload`.
|
|
*/
|
|
export async function runCron<T>(
|
|
jobName: string,
|
|
fn: () => Promise<T>
|
|
): Promise<{ ok: true; payload: T } | { ok: false; error: string }> {
|
|
let runId: string | null = null;
|
|
try {
|
|
const row = await prisma.cronRun.create({
|
|
data: { jobName, status: "RUNNING" },
|
|
select: { id: true },
|
|
});
|
|
runId = row.id;
|
|
} catch (err) {
|
|
console.error(`[cron-runner] gagal create row ${jobName}`, err);
|
|
// Lanjut tanpa log — jangan blok cron karena DB log gagal.
|
|
}
|
|
|
|
try {
|
|
const payload = await fn();
|
|
if (runId) {
|
|
await prisma.cronRun
|
|
.update({
|
|
where: { id: runId },
|
|
data: {
|
|
status: "SUCCESS",
|
|
finishedAt: new Date(),
|
|
payload: payload as unknown as object,
|
|
},
|
|
})
|
|
.catch((e) => console.error(`[cron-runner] gagal update SUCCESS`, e));
|
|
}
|
|
return { ok: true, payload };
|
|
} catch (err) {
|
|
const message =
|
|
err instanceof Error ? err.message : "Unknown cron failure";
|
|
if (runId) {
|
|
await prisma.cronRun
|
|
.update({
|
|
where: { id: runId },
|
|
data: {
|
|
status: "FAILED",
|
|
finishedAt: new Date(),
|
|
errorMessage: message,
|
|
},
|
|
})
|
|
.catch((e) => console.error(`[cron-runner] gagal update FAILED`, e));
|
|
}
|
|
return { ok: false, error: message };
|
|
}
|
|
}
|