Skip to content
ABRQ DATADocs Abrq DIP · latest
Product page Request a trial
On this page

Schedules

Purpose#

A schedule makes a job run without anyone pressing a button. You give it a cron expression; Abrq DIP triggers the job when the expression comes due.

One rule shapes everything on this page:

Note. Schedules attach to jobs, not to individual tasks. Per-task schedules were removed. If you want a single task to run on a timer, put it in a job of its own and schedule that job. This keeps one answer to "what is running right now" instead of two competing timers on the same table.

Schedules live at /schedules.

Before you begin#

  • A job to attach the schedule to. Create it first — see Jobs.
  • A working manual run. Schedule a job you have already run by hand at least once. A schedule is a bad place to discover that a connector role does not resolve.
  • Times are UTC. Cron expressions are evaluated in UTC, and every time shown on the schedules dashboard — last fire, next fire — is UTC. There is no per-schedule timezone. If your business day is Asia/Riyadh (UTC+3), a 02:00 local batch is 0 23 * * * UTC on the previous day. Work the offset out once and write it in the schedule's description.

Required role#

Action Global role Project capability Typical project role
View schedules viewer or higher schedule.view any project member
Create, edit, pause, resume, delete a schedule editor or higher schedule.manage Developer (unprotected environments only), Maintainer, Owner

schedule.manage is one of the six environment-gated write capabilities. In a protected environment a Developer cannot create or change a schedule and is refused with the reason protected_environment; a Maintainer or Owner can. See Environments and promotion.

The global admin role is an implicit Owner on every project.

Create a schedule#

  1. Go to /schedules and choose New schedule, or open a job and add a schedule from there.
  2. Pick the job to run.
  3. Enter the cron expression.
  4. Give it a name and, ideally, a description that records the intent and the local-time equivalent.
  5. Save. The schedule is enabled, and its next fire time is computed immediately.

Cron expressions#

Expressions are validated with croniter when you save. An expression that croniter cannot parse is rejected at save time, so a schedule never sits in the system quietly failing to be understood.

Standard five-field cron, all times UTC:

┌─ minute (0–59)
│ ┌─ hour (0–23)
│ │ ┌─ day of month (1–31)
│ │ │ ┌─ month (1–12)
│ │ │ │ ┌─ day of week (0–6, Sunday = 0)
│ │ │ │ │
* * * * *
Intent Expression
Every hour, on the hour 0 * * * *
Every 15 minutes */15 * * * *
Daily at 01:30 UTC 30 1 * * *
Weekdays at 06:00 UTC 0 6 * * 1-5
First of the month, 00:00 UTC 0 0 1 * *

Tip. Avoid scheduling everything on the hour. Ten jobs at 0 * * * * all wake up in the same beat tick and contend for the same connectors and workers. Spread heavy jobs across the hour — 7 * * * *, 23 * * * *, and so on.

How firing works#

A beat tick runs every 60 seconds. On each tick Abrq DIP:

  1. Finds every enabled schedule whose next fire time has come due.
  2. Advances the next fire time first, before triggering anything.
  3. Triggers the job run.

Step 2 is the important one. Because the next fire time moves forward before the run is dispatched, a job that takes 90 minutes under an hourly schedule is never double-fired by the tick that lands while it is still running — the schedule has already moved on.

Two consequences worth planning around:

  • The finest useful granularity is one minute. A cron expression cannot fire more often than the tick.
  • A fire can land up to 60 seconds after the nominal cron time. Schedules are for batch work, not for sub-minute latency.

Note. Advancing the fire time first means a missed window is skipped, not queued. If the platform is down across three hourly slots, you get one run when it comes back — not three catch-up runs.

Pause and resume a schedule#

Pausing is the safe way to stop a recurring run without losing its definition.

  1. Open the schedule from /schedules.
  2. Choose Pause.

A paused schedule is skipped by every beat tick. Its cron expression, its job binding, and its history stay intact. Resume it and the next fire time is recomputed from the current moment forward — resuming does not replay the runs that were skipped while it was paused.

Pause rather than delete when you are:

  • Freezing batch work during a migration or an upgrade window.
  • Investigating a failing job and do not want another run starting mid-triage.
  • Temporarily handing a load over to a manual process.

Delete a schedule only when the recurrence itself is retired. Deleting a schedule does not delete the job, and it does not delete run history.

Read the schedules dashboard#

/schedules lists every schedule you can see, with:

Column What it tells you
Name The schedule's label.
Job The job it triggers. Follow it through to the job's run history.
Cron The expression, as saved.
Enabled Whether beat ticks will act on it. A paused schedule reads as disabled.
Next fire The next UTC time the beat tick will trigger it.
Last fire The last UTC time it triggered.

Two quick reads that catch most problems:

  • A next-fire time in the past means the schedule is paused or the beat worker is not running. Check the schedule's enabled state first, then check with your platform administrator that background processing is healthy — see Background processing.
  • A last-fire time that keeps advancing while the job's run history does not means the trigger is firing and the run is being refused. Open the job's runs and read the refusal — the next section is the usual cause.

Field reference#

Field Type Notes
Name text Identifies the schedule in lists and logs.
Description text Optional. The right place to record the local-time equivalent of the UTC cron.
Job reference The job to trigger. Required. A schedule cannot target a task.
Cron expression text Five-field cron, validated with croniter at save time. Evaluated in UTC.
Enabled boolean Off means paused: beat ticks skip it.
Next fire timestamp (read-only) UTC. Advanced by the tick before the run is triggered.
Last fire timestamp (read-only) UTC.

Failure modes#

A scheduled run against a protected environment is refused#

This is the failure mode most likely to bite you, because it is invisible until you look.

A job run targeting a protected environment is refused before any task executes unless every connector role its tasks require resolves in that environment. When the trigger is a schedule, nobody is watching the screen: the schedule's last-fire time advances, the job records a refused run, and no data moves.

Cause: the environment is missing a source or destination binding that one of the job's tasks needs — typically because a task was promoted into the environment but the environment's connector bindings were never completed. Resolution is fail-loud by design and never falls back to another environment's connector.

Fix:

  1. Open the refused job run and read which environment and which role are named.
  2. Go to that environment and bind a connector to that role — see Environments and promotion.
  3. Run the job manually once to confirm, then leave the schedule to it.

Tip. Configure a run_failed notification on the job so a refusal reaches a person instead of sitting in a table. See Notifications and alerts.

Other failures#

What you see Cause Fix
Save rejected, invalid cron croniter could not parse the expression. Correct the expression — five fields, UTC.
Schedule fires up to a minute late Expected. The beat tick runs every 60 seconds. None. Do not use schedules for sub-minute work.
Missed windows are not replayed after downtime Expected. The next fire time is advanced before triggering; there is no catch-up queue. Run the job manually once to fill the gap.
The job never appears to double-run despite overlapping durations Expected, and intended — the fire time advances before dispatch. None.
Cannot create or pause a schedule; reason protected_environment You hold the Developer role and the environment is protected. Ask a Maintainer or Owner.
Scheduled run fails with 403 license_expired The deployment's license has expired; runs are refused. See Expiry and clock.

See also#