Jobs Engine
Cron-based scheduled background tasks. Implemented in Milestone 6.
Location
src/core/jobs/
types.ts—JobContext,JobsEngine,RegisteredJob,JobRunLogcron.ts— hand-rolled 5-field cron parser andgetNextRundiscover.ts— scansjobs/**/*.ts, validates exportscreate-jobs-engine.ts— scheduler, execution, retry, lifecycle eventswatch.ts—fs.watchdebounced reload for hot reload
Job Definition
export const schedule = "0 3 * * *";
export default async ({ db, logger }) => {
logger.info("Running cleanup");
};
- Path:
{projectRoot}/jobs/(sibling tobakend.json) - One job per
.tsfile - Missing directory is skipped (no error)
Cron Syntax
Five fields: minute hour day month weekday
| Field | Range |
|---|---|
| minute | 0–59 |
| hour | 0–23 |
| day | 1–31 |
| month | 1–12 |
| weekday | 0–6 (Sunday = 0) |
Supports *, */n, ranges (9-11), and lists (1,15).
Engine API
const jobs = createJobsEngine({
eventBus, db, logger,
jobsDir: join(projectDir, "jobs"),
watch: false,
});
await jobs.load();
jobs.list(); // RegisteredJob[]
jobs.getRuns("cleanup"); // JobRunLog[] (in-memory, last 50)
jobs.reload();
jobs.shutdown();
Wired into start() via StartResult.jobs.
Lifecycle Events
Emitted by the jobs engine (source: jobs):
job.started— payload:name,filePath,schedule,runIdjob.completed— same +durationMs,attemptjob.failed— same +error,attempt
Retry Policy
- 3 attempts per scheduled run (1 initial + 2 retries)
- 5 second fixed delay between retries
- Failures never crash the process
Scheduler
- One run at a time per job; overlapping ticks are skipped
- Uses
setTimeoutto next due time plus a 1s safety tick
Hot Reload
bak dev— starts withwatch: truefor functions and jobsbak start --watch— same behavior via flag- Uses
fs.watchwith 100ms debounce
Deferred
bak jobsCLI management- Persistent run history in SQLite
- Event-triggered jobs
- Distributed execution / queues