Cron, intervals, and one-shot — one trigger type

Run scheduled jobs without running a server

The job that has to run at 3am is rarely the interesting part of your product, but it is the part that pages you when the box it lives on goes away. Centrali runs it as a managed trigger instead.

Free to start. No credit card.

The usual options all have a tax

Scheduled work is easy to start and annoying to keep. Every common approach trades one problem for another.

A cron line on a VM

Works until the box is rebuilt, resized, or forgotten. The schedule lives in a file nobody has read since it was written, and nothing tells you it stopped.

A scheduler in your app process

Now it runs once per replica. You scale to three pods and the nightly email goes out three times, so you bolt on a lock and maintain that too.

A cloud scheduler wired to a function

Two services, two IAM policies, and two places to look when it did not fire. The schedule and the code it runs drift apart.

Three ways to say when

Schedules are not a separate product — they are an execution type on a trigger, configured the same way as everything else that runs your functions.

Cron expression

Standard 5-field cron, running in the IANA timezone you name rather than only UTC — so "every weekday at 09:00 in America/Chicago" survives daylight saving without arithmetic.

0 9 * * 1-5

Interval

Every N seconds or minutes, for work that cares about cadence rather than clock time. This is the option to reach for when you need something faster than once a minute.

every 30s

One-shot

Fires at a single future timestamp and is then done. Useful for a scheduled send or a trial expiry — anything tied to one date rather than a recurring cadence.

2026-09-01T14:00:00Z

The job itself is a function

Scheduled runs carry no request and no payload — executionParams is empty. Anything the job needs comes from triggerParams, which you set on the trigger and can encrypt.

js
async function run() {
// Scheduled runs have no payload. Config comes from the trigger.
const graceDays = triggerParams.graceDays;
const today = new Date().toISOString().slice(0, 10);
const overdue = await api.queryRecords('invoices', {
where: {
and: [
{ 'data.status': { eq: 'unpaid' } },
{ 'data.dueAt': { lt: today } },
],
},
page: { limit: 100 },
});
for (const invoice of overdue.data) {
await api.updateRecord(invoice.id, { status: 'overdue' });
}
return { ok: true, marked: overdue.data.length, graceDays };
}

api.updateRecord takes the record id, not the collection slug — only createRecord and queryRecords need the collection.

What the scheduler actually promises

Worth stating plainly, because scheduling is a place where vague wording costs people data.

It survives a pod failure

The scheduler runs multiple instances with leader election, so losing one costs about five seconds, not the schedule.

You can pause without deleting

A paused scheduled trigger is removed from the scheduler and put back when you resume it. The definition, its history, and its params stay exactly where they were.

Secrets in job config are encrypted at rest

Params marked as secrets are encrypted at rest, including in the trigger version history.

Cron does not go below one minute

Cron expressions are 5-field, so a minute is the floor. Use an interval schedule when you need a shorter cadence.

It is not exactly-once

The scheduler acknowledges a dispatch best-effort and schedules the next tick regardless. Build the job so that running twice is safe.

A missed tick is not backfilled

After a failover the next tick is scheduled; the skipped one is not replayed. If a run must eventually happen, have the job find its own outstanding work rather than assuming every tick fired.

You can see whether it ran

Every trigger tracks success, failure, and duration per day, and every change to a trigger is versioned — so "when did this start failing" and "what changed" are both answerable after the fact.

To be straight about the gap: Centrali does not yet notify you when a scheduled job starts failing. The history is there and you can query it, but today you go look.

What people actually schedule

Nightly reconciliation

Walk yesterday’s records, compare against the provider, and write down what disagrees.

Expiring and sweeping

Move stale carts, unpaid invoices, or abandoned drafts into a terminal state on a schedule.

Polling an API that has no webhook

Not everything you depend on will call you. An interval schedule plus an allow-listed outbound call covers the ones that will not.

Periodic rollups

Fold raw rows into a daily summary collection so dashboards read one record instead of scanning thousands.

Questions people ask first

Can I run a cron job every 30 seconds?

Not with cron — expressions are 5-field, so one minute is the floor. Use an interval schedule for sub-minute cadence; it is the same trigger, configured differently.

What timezone do cron schedules run in?

Whichever IANA timezone you name, not just UTC. That means a schedule pinned to local business hours keeps working across daylight saving changes without you recomputing the expression.

What happens if the scheduler loses a node mid-schedule?

The scheduler runs multiple instances with leader election, so a pod failure costs roughly five seconds rather than the schedule. It is not exactly-once, though, and a tick missed during a failover is not backfilled — the next one is simply scheduled.

Does my scheduled function receive a payload?

No. For scheduled runs executionParams is empty. Static configuration comes from triggerParams, which you set on the trigger and can mark as encrypted.

Can I pause a job without losing it?

Yes. Pausing removes a scheduled trigger from the scheduler and resuming puts it back, leaving the definition, params, and history intact.

Can I schedule something in the past to force a run?

No — a one-shot schedule set in the past is rejected when you write it. To run a function immediately, invoke it on demand instead.

Give the 3am job somewhere to live

A schedule, a function, and a history of every run — without a box whose only job is staying awake.

Free to start. No credit card.