import { sql } from "@/db"; import { stats } from "@/lib/jobs/queue"; import { fmtDateTime } from "@/lib/utils"; import { EnqueueButton } from "@/components/admin/enqueue-button"; import { JobRowActions } from "@/components/admin/job-actions"; export default async function Jobs({ searchParams }: { searchParams: Promise<{ status?: string }> }) { const { status } = await searchParams; const rows = await sql`SELECT id, kind, payload, status, attempts, max_attempts AS "maxAttempts", run_at AS "runAt", finished_at AS "finishedAt", last_error AS "lastError", result FROM jobs ${status ? sql`WHERE status=${status}` : sql``} ORDER BY id DESC LIMIT 150`; const st = await stats(); const [lastBackup] = await sql`SELECT finished_at AS "finishedAt", result FROM jobs WHERE kind='backup' AND status='succeeded' ORDER BY finished_at DESC LIMIT 1`; return (
Durable queue in PostgreSQL. Schedule (America/Toronto): link sweep 03:10 daily · freshness 03:40 · embeddings 04:00 (if a provider is configured) · encrypted backup 04:20. Retries use exponential backoff; after the maximum attempts a job is marked dead.
Last successful backup: {lastBackup ? `${fmtDateTime(lastBackup.finishedAt)} · ${(lastBackup.result as any)?.bytes ?? "?"} bytes${(lastBackup.result as any)?.remote ? ` · remote ${(lastBackup.result as any).remote}` : ""}` : "none recorded"}
| # | Kind | Payload | Status | Attempts | Run at | Finished | Result / error | |
|---|---|---|---|---|---|---|---|---|
| {j.id} | {j.kind} | {JSON.stringify(j.payload)} | {j.status} | {j.attempts}/{j.maxAttempts} | {fmtDateTime(j.runAt)} | {fmtDateTime(j.finishedAt)} | {j.lastError ? j.lastError.split("\n")[0] : JSON.stringify(j.result)} |