Files
setrip/lib/cron-runner.ts
T

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 };
}
}