How to Implement Recurring Jobs with cron-parser in Agent-Native
Agent-Native provides a lightweight wrapper around the cron-parser library in packages/core/src/jobs/cron.ts that exposes three pure functions—nextOccurrence, isValidCron, and describeCron—to validate, describe, and schedule cron-based recurring jobs within the framework's job queue system.
BuilderIO/agent-native includes a robust job scheduling system that leverages the cron-parser library for recurring task execution. The framework provides pure utility functions in packages/core/src/jobs/cron.ts that handle cron expression parsing, validation, and human-readable description generation, allowing developers to implement recurring jobs safely without side effects.
Understanding the Cron Utilities in Agent-Native
The cron wrapper exports three pure functions that form the foundation of recurring job handling in Agent-Native.
Core Functions Overview
The wrapper in packages/core/src/jobs/cron.ts provides:
nextOccurrence(cronExpr, after?): Returns aDateobject representing the next execution time for a given cron expression, optionally calculated after a specific dateisValidCron(cronExpr): Validates whether a cron expression is parseable by attempting to parse it within a try-catch blockdescribeCron(cronExpr): Generates human-readable descriptions like "Every weekday at 9 AM" by normalizing and analyzing the expression's fields
These utilities are completely side-effect free and covered by comprehensive unit tests in packages/core/src/jobs/cron.spec.ts.
Creating Recurring Jobs in Agent-Native
Recurring jobs in Agent-Native are stored in the jobs table within the core SQL schema. Each record contains the cron expression, target action name, payload, and computed nextRunAt timestamp.
Validating and Describing Cron Expressions
Before persisting a job, use isValidCron to validate the expression and describeCron to generate a user-friendly description for admin interfaces:
// src/actions/recurring.ts
import { defineAction } from '@agent-native/core/actions';
import {
isValidCron,
describeCron,
nextOccurrence,
} from '@agent-native/core/jobs/cron';
interface ReportPayload {
reportId: string;
}
export const createDailyReportJob = defineAction({
name: 'createDailyReportJob',
input: { reportId: 'string' },
async run({ reportId }) {
const cron = '0 9 * * *'; // 09:00 UTC every day
if (!isValidCron(cron)) {
throw new Error('Invalid cron expression');
}
const description = describeCron(cron); // "Every day at 9 AM"
const firstRun = nextOccurrence(cron);
await db.insert('jobs', {
cron,
targetAction: 'sendDailyReport',
payload: { reportId } as ReportPayload,
nextRunAt: firstRun,
description,
});
return { ok: true, nextRunAt: firstRun, description };
},
});
Processing Recurring Jobs with a Scheduler
The scheduler service queries the jobs table for entries where nextRunAt is less than or equal to the current time, dispatches the target action using Agent-Native's invocation API, and recomputes the next occurrence.
The Tick Loop Implementation
See templates/brain/jobs/process-ingest-queue.ts for a reference implementation of a job processor. Your recurring job worker should follow this pattern:
// src/server/jobs/worker.ts
import { db } from '@agent-native/server/db';
import { nextOccurrence } from '@agent-native/core/jobs/cron';
import { invokeAction } from '@agent-native/core/actions';
export async function processDueJobs() {
const now = new Date();
const dueJobs = await db.select('jobs', {
where: { nextRunAt: { lte: now } },
});
for (const job of dueJobs) {
await invokeAction(job.targetAction, job.payload);
const nextRun = nextOccurrence(job.cron, now);
await db.update('jobs', job.id, { nextRunAt: nextRun });
}
}
This function runs at your desired interval—whether via setInterval in a Nitro plugin or a cloud-scheduled task—to continuously process the recurring job queue.
Summary
- Agent-Native wraps
cron-parserinpackages/core/src/jobs/cron.tsto provide three pure functions:nextOccurrence,isValidCron, anddescribeCron - Job creation involves validating the cron expression, computing the first run time, and persisting to the
jobstable with the target action and payload - Job processing requires a tick loop that queries due jobs, invokes the target action, and updates
nextRunAtusingnextOccurrence - The wrapper normalizes the
@midnightalias and handles timezone considerations automatically - All utilities are pure functions with no side effects, making them safe to use in plugins, extensions, or frontend code for previewing schedules
Frequently Asked Questions
How does Agent-Native handle invalid cron expressions?
The isValidCron function in packages/core/src/jobs/cron.ts wraps the parser in a try-catch block and returns a boolean indicating validity. This allows you to reject malformed expressions at job creation time before they reach the database, preventing scheduler errors downstream.
What is the @midnight alias and why does it need normalization?
The @midnight alias is a historic cron shorthand that cron-parser v5 misinterprets. Agent-Native includes an internal ALIAS_MAP in the cron wrapper that normalizes this alias to the correct expression before parsing, ensuring consistent behavior across different versions of the underlying library.
Can I use these cron utilities on the frontend?
Yes. Because nextOccurrence, isValidCron, and describeCron are pure functions with no side effects, you can import them from @agent-native/core/jobs/cron into frontend code to preview schedule descriptions or validate expressions before submitting them to the server, reducing unnecessary API calls.
How do I test recurring jobs in Agent-Native?
Unit tests for the cron utilities are located in packages/core/src/jobs/cron.spec.ts and cover expression normalization, timezone handling, and description generation. For integration testing, you can mock the nextOccurrence function to return specific dates, or use the patterns shown in templates/brain/jobs/process-ingest-queue.ts to test your job processor logic independently of the actual clock.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →