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 (

Jobs & crawler

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

{st.map((s) => {s.kind} · {s.status}: {s.n})}
{rows.map((j) => )}
#KindPayloadStatusAttemptsRun atFinishedResult / 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)}
); }