CronJob
A CronJob runs a handler on a schedule. Use it for periodic work — daily reports, hourly aggregations, weekly retention sweeps.
Quick example
import { Project, CronJob, Database } from '@sprintsail/sdk';
export const app = new Project('orders');
export const db = new Database(app, 'orders', { engine: 'postgres', version: '16' });
export const dailyReport = new CronJob(app, 'daily-report', {
handler: './src/handlers/daily-report.ts',
schedule: 'cron(0 9 * * ? *)', // every day at 09:00 UTC
memory: 512,
timeout: 300,
bindings: { db },
});
Handler:
import { db } from '../../infra.js';
export default async function handler() {
const rows = await db.query(
"SELECT count(*) FROM orders WHERE placed_at >= now() - interval '1 day'",
);
console.log({ ordersToday: rows[0].count });
}
Config
interface CronJobConfig {
handler: string;
runtime?: 'nodejs22' | 'nodejs20' | 'python3.12';
schedule: string; // see "Schedule formats" below
memory?: number; // MB, default 256
timeout?: number; // seconds, default 30
env?: Record<string, string>;
bindings?: Record<string, Database | Bucket | Secret | Queue>;
}
Schedule formats
The SDK accepts a permissive schedule string and translates it per target:
| Format | Example | Translates to (AWS) | Translates to (Runtime) |
|---|---|---|---|
| 5-field Linux cron | 0 9 * * * | cron(0 9 * * ? *) | passed through |
| 6-field EventBridge cron | cron(0 9 * * ? *) | passed through | dropped year/? |
rate(N minute/hour/day) | rate(15 minutes) | passed through | converted to */15 * * * * |
| Shortcuts | @hourly, @daily, @weekly, @monthly, @yearly | converted | passed through (K8s supports) |
Target mapping
| Target | Maps to | Notes |
|---|---|---|
aws | Lambda + EventBridge Scheduler rule | Same Lambda constraints as Function. |
sprintsail-runtime | Native Kubernetes CronJob (batch/v1) | concurrencyPolicy: Forbid. History limits: 3 successful / 3 failed jobs retained. |
Concurrency
By default, only one invocation runs at a time on the runtime (concurrencyPolicy: Forbid). On AWS, EventBridge fires the schedule and Lambda concurrency limits apply globally — the SDK doesn't add per-CronJob concurrency control there.
If your schedule is faster than your handler runs, consider increasing timeout or switching to a Worker consuming from a queue instead.
Time zones
Schedules are interpreted as UTC on both targets. Convert local times yourself.