import { join } from 'path' import type { CronJob } from './schedules' import { getNextRun } from './scheduler' const APPS_DIR = process.env.APPS_DIR! export async function executeJob(job: CronJob, onUpdate: () => void): Promise { if (job.state === 'disabled') return job.state = 'running' job.lastRun = Date.now() onUpdate() const cwd = join(APPS_DIR, job.app, 'current') try { const proc = Bun.spawn(['bun', 'run', job.file], { cwd, env: { ...process.env }, stdout: 'pipe', stderr: 'pipe', }) const [stdout, stderr] = await Promise.all([ new Response(proc.stdout).text(), new Response(proc.stderr).text(), ]) const code = await proc.exited job.lastDuration = Date.now() - job.lastRun job.lastExitCode = code job.lastError = code !== 0 ? stderr || 'Non-zero exit' : undefined job.state = 'idle' job.nextRun = getNextRun(job.id) // Log result console.log(`[cron] ${job.id} finished: code=${code} duration=${job.lastDuration}ms`) if (stdout) console.log(stdout) if (stderr) console.error(stderr) } catch (e) { job.lastDuration = Date.now() - job.lastRun job.lastExitCode = 1 job.lastError = e instanceof Error ? e.message : String(e) job.state = 'idle' console.error(`[cron] ${job.id} failed:`, e) } onUpdate() }