CronJob Class#
Create a file in cronsPath, extend CronJob, and export a main()
function returning the job instance:
import 'package:zonai_schema/zonai_schema.dart';
final class DailyReportJob extends CronJob {
DailyReportJob()
: super(
name: 'daily-report',
schedule: Schedule.parse('0 8 * * *'), // 8:00 AM daily
);
@override
Future<void> run() async {
// job logic here
}
}
DailyReportJob main() => DailyReportJob();
-
One job per file. Every
.dartfile undercronsPathis compiled in, including files in subdirectories, and each one'smain()must return aCronJob. -
The constructor is not
const.Schedule.parseis not a const constructor, so a job built from it cannot beconsteither. -
Keep
nameunique. Catch-up and run history look jobs up byname, and manual runs start the first job with a matching name. Two jobs with the same name share one history.
Constructor Parameters#
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
name |
String |
Yes | — |
Unique identifier; used in
_cron_jobs
history and on-demand invocation by name (dev TUI or
POST /crons/run?name=<name>
)
|
schedule |
Schedule |
Yes | — | When to run |
strict |
bool |
No | true |
true
skips ticks missed while the server was down;
false
catches up once on startup
|
runOnStartup |
bool |
No | false |
Run once immediately when the crons worker starts |
enabled |
bool |
No | true |
Not enforced yet. The scheduler runs the job whatever this is set to, so delete or move the file to stop a job |
Schedule#
Schedules use standard cron syntax via Schedule.parse('...'):
Schedule.parse('0 3 * * *'), // every day at 3:00 AM
Schedule.parse('*/15 * * * *'), // every 15 minutes
Schedule.parse('0 9 * * 1'), // every Monday at 9:00 AM
Schedule.parse('0 0 1 * *'), // first of every month at midnight
Quick reference: minute hour day-of-month month day-of-week. A sixth, leading field adds seconds. Use
crontab.guru to build expressions. Times are the server's local time.
You can also build a schedule from explicit fields:
Schedule(minutes: [0, 30], hours: [9, 17], weekdays: [1, 2, 3, 4, 5]),
Schedule comes from the cron package, which
package:zonai_schema/zonai_schema.dart re-exports. That package's docs cover the full field syntax (*, lists, ranges, steps).
strict#
-
strict: true(default): the job runs only on its schedule. Ticks missed while the server was down are skipped. -
strict: false: if a tick was missed since the job's last recorded run, the job runs once as soon as the crons worker starts.
See Catch-Up Logic for details.
runOnStartup#
When true, the job runs once as soon as crons start with the server, whatever its schedule says. Useful for initialization tasks or for making sure a cleanup always runs after a deployment.
The run() Method#
Write job logic in run(). The get, mutate, email,
push and logger globals are all available (see Side Effects in Cron Jobs):
@override
Future<void> run() async {
final rows = await get.many(
tableName: 'subscriptions',
where: Lt('expires_at', DateTime.now()),
) ?? [];
logger.info('Found ${rows.length} expired subscriptions');
for (final row in rows) {
mutate.update.one(
table: 'subscriptions',
updates: [Update.column('status', .literal('expired'))],
where: Eq('id', row['id']!),
);
}
}
Errors thrown from run() are caught and recorded on the run's _cron_jobs row (failed,
error, stack_trace). They do not crash the server.