The scheduler is Jetstack's time-based execution queue. It stores planned automation runs and processes them when their scheduled time arrives.
Unlike Types, Properties, or Modules, the scheduler is not primarily a design-time metadata resource. It is an operational surface. Its main purpose is to let you define when an automation should run, whether it should repeat, and whether the platform should keep an execution log.
The scheduler is how you move work away from immediate user interaction and into time-based processing.
Use it when:
- an action should happen later rather than now
- a process should repeat on a cadence
- you need reminders, follow-ups, escalations, or housekeeping
- an automation should be triggered without a user opening a screen or clicking a button
Typical examples:
- send a follow-up automation 3 days after record creation
- repeat an automation every morning
- retry a maintenance or reconciliation routine every hour
- generate periodic digests
The scheduler has two layers:
- the task definition you create or store
- the queue behavior that the runtime applies when the task becomes due
This chapter explains both:
- each task field and what it means
- which fields are configurable in the scheduler screen
- which fields exist mainly for API or automation-driven scheduling
- what happens when a task is repeated, skipped, cancelled, or logged
Use this chapter together with:
Keep these distinctions clear:
- a scheduler task points to one target automation
run_at defines the next planned execution time
next_run defines how the next occurrence is calculated after execution time arrives
last_run defines when recurrence should stop
skip suppresses execution of the current queued occurrence
log_runs controls whether execution details are written into the scheduler log
request stores the argument payload passed into the automation
The scheduler does not store business logic by itself. It stores timing and execution instructions for an automation that already exists elsewhere in the platform.
Jetstack uses the scheduler in two main ways.
The scheduler screen lets an operator create a task by choosing:
- an automation
- the planned run time
- optional recurrence
- optional recurrence end time
- whether logging should be enabled
This is the simplest operational path and is useful for:
- ad hoc scheduling
- testing a scheduled automation
- operator-managed recurring jobs
The same scheduler can also be used from automation actions and platform API calls. In that mode, a task can be created with explicit argument payload in addition to the normal timing fields.
This matters because the stored task model is slightly richer than the form shown in the scheduler page. Some fields, such as the serialized request payload, may be populated by automations or API integrations even when the manual screen does not expose them directly.
The scheduler screen exposes the following task inputs when creating a new task:
| Option |
What it controls |
How to configure it |
Notes |
automation |
Which automation should run when the task becomes due. |
Select an automation from the list of available automations. |
Required. |
run_at |
Exact planned date and time for the first occurrence. |
Enter a date-time in the form field. |
Required. Stored as the queue time for this task. |
next_run |
Relative recurrence definition for creating the next occurrence. |
Enter a PHP-compatible relative time expression such as +1 day or +1 week. |
Optional. If empty, the task runs once. |
last_run |
End boundary for recurrence. |
Enter the latest allowed boundary for generating another occurrence. |
Optional. Used only when recurrence is enabled. |
log_runs |
Whether executions should be written into the scheduler log. |
Check or uncheck the checkbox. |
Enabled by default in the form. |
The stored task model also includes:
| Field |
Purpose |
How it is populated |
request |
Serialized argument payload passed into the automation as scheduler arguments. |
Usually programmatically, not from the manual screen. |
skip |
One-time instruction to ignore execution of the queued occurrence. |
Set later through the scheduler screen action. |
uuid |
Stable task identifier. |
Generated automatically by the platform. |
created_on, owner, created_by |
Operational metadata about task creation. |
Generated by the platform. |
This selects the automation that the scheduler should execute.
How to configure it:
- open the scheduler's new-task form
- choose one automation from the select list
What it means:
- the scheduler stores the automation ID in the task
- when the task becomes due, the scheduler loads that automation and calls its runtime
- the automation receives scheduler context including the stored task arguments
What to choose:
- choose an automation that is intentionally built to run without an immediate UI action
- scheduled automations are especially appropriate, but the scheduler can execute any automation that can run correctly from queued context
Practical guidance:
- keep scheduled automations focused and deterministic
- avoid choosing automations that depend on transient UI state unless they were designed for it
- if the automation expects arguments, prefer scheduling it programmatically so the
request payload is filled explicitly
This is the planned execution time of the current queued task.
How to configure it:
- enter a date and time into the
datetime-local field
- the entered value is converted to a server-side date-time and stored as the due time
What it means:
- the task becomes eligible for execution when the scheduler processes tasks with
run_at earlier than the processing cutoff
- the scheduler processes due tasks in ascending
run_at order
Important behavior:
- the scheduler page's "Run until now" action executes tasks due up to the current time
- the background cron route also processes due tasks on a schedule
- a task is not executed continuously at its exact timestamp on its own; it is executed the next time the scheduler runner processes due work
Use it for:
- one-off delayed execution
- the first occurrence of a recurring task
This field turns a one-time task into a recurring task.
How to configure it:
- leave it empty for a one-time task
- enter a relative time expression for recurrence, such as:
+1 hour
+1 day
+1 week
+1 month
next monday
What it means:
- when a due task is processed, the scheduler calculates the next occurrence by taking the current task's
run_at value and calling date-time modification logic with the next_run expression
- the result becomes the
run_at value of the next queued task
This is a very important detail:
- recurrence is calculated from the current planned run time, not from the actual moment when the queue processor happened to run
That behavior helps avoid drift. For example:
- task
run_at = 2026-04-11 09:00
next_run = +1 day
- if the runner processes the task at
09:04, the next task is still based on 09:00, not 09:04
Practical guidance:
- use simple, explicit relative time expressions
- avoid ambiguous text
- prefer expressions whose meaning is obvious to future operators
Operational caution:
- the scheduler form accepts
next_run as free text
- the runtime later interprets it through PHP date-time modification behavior
- if the expression is invalid or unclear, recurrence may fail when the task is processed
This field defines the upper boundary for recurrence.
How to configure it:
- leave it empty if the task should keep recurring without an end boundary
- enter a date and time if recurrence should stop after a certain point
What it means:
- when the current occurrence becomes due, the scheduler calculates the next occurrence using
next_run
- it only inserts that next task if the calculated next run is earlier than
last_run
This means the boundary is effectively exclusive for the generated next occurrence.
Example:
run_at = 2026-04-11 09:00
next_run = +1 day
last_run = 2026-04-14 09:00
Generated next tasks:
2026-04-12 09:00
2026-04-13 09:00
Not generated:
because the scheduler checks whether the next planned run is strictly earlier than last_run.
Use last_run when:
- a recurring reminder should stop after a fixed campaign window
- a temporary maintenance loop should expire automatically
- the scheduler should enforce a hard end date without requiring an operator to cancel the task manually
This controls whether successful scheduler execution attempts are written to the scheduler log table.
How to configure it:
- leave it checked to keep a run log
- uncheck it for low-value, high-frequency, or noise-heavy tasks
What it means:
- when enabled, the scheduler stores:
- planned run time
- actual execution time
- automation ID
- request payload
- automation errors
What it does not do:
- it does not change whether the automation runs
- it does not control application-wide event logging
- it does not automatically guarantee business-level observability beyond the scheduler log content
Use it for:
- important recurring business processes
- troubleshooting
- tasks where operators need evidence of execution history
Disable it when:
- the task is very frequent and the log would become noisy
- failures are handled elsewhere and the scheduler log is not operationally useful
This is the stored payload of scheduler arguments passed into the automation at run time.
How to configure it:
- the standard scheduler screen does not expose a dedicated form field for arguments
- the field is normally populated when tasks are created from automations or API calls
What it means:
- when the automation runs, the scheduler unserializes this payload and passes it into the automation as
args
- this is the main way to give a scheduled automation task-specific input
Use it when:
- one automation should be scheduled many times with different parameters
- the scheduled run must remember business context captured earlier
- an automation schedules another automation for delayed execution
Example use cases:
- schedule a reminder automation with a specific object ID
- schedule a timeout follow-up with escalation metadata
- schedule a digest job with a target audience or period definition
Once a task exists, the scheduler screen also lets an operator change how that queued occurrence is handled.
This marks the queued occurrence so it will not be executed when it becomes due.
How to configure it:
- use the
Skip action in the scheduler list
What it means:
- the task stays in the queue until it becomes due and is processed
- when processed, the scheduler removes the current task and does not run its automation
Important recurring-task behavior:
- recurrence is calculated before the current due task is discarded
- this means skipping one occurrence of a recurring task normally skips only that occurrence
- the next occurrence is still created if recurrence rules allow it
This is useful when:
- you want to suppress one run without dismantling the recurring schedule
- a planned run is no longer needed, but future runs should remain in place
Cancel removes the queued task entirely.
How to configure it:
- use the cancel action in the scheduler list
What it means:
- the current queued record is deleted immediately
- it will not be processed later
Difference from skip:
skip keeps the due occurrence in the queue until it is processed and then suppresses execution
- cancel removes the occurrence right away
Use cancel when:
- the task should disappear from the queue now
- a scheduled run was created by mistake
- the process should no longer continue in that queued form
The scheduler list also lets operators enable or disable logging for an already queued task.
How to configure it:
- use the bell actions in the scheduler list
What it means:
- the task record's
log_runs flag is updated
- future execution of that queued occurrence uses the new logging setting
This is useful when:
- a task suddenly becomes operationally important
- a noisy repeating task should stop producing scheduler log records
¶ Execution Order And Runtime Behavior
When the scheduler processes due tasks, it performs the following steps:
- fetch tasks with
run_at earlier than the chosen execution cutoff
- process them in ascending
run_at order
- if recurrence exists, calculate and insert the next occurrence
- delete the current queued task
- if the current task is marked
skip, stop there
- load the target automation
- pass scheduler arguments into the automation
- optionally log the run
This sequence has several important consequences.
If a recurring task is due, the next occurrence is normally inserted before the current occurrence is executed.
That means:
- a failure in the current automation does not automatically prevent the next occurrence from being created
- recurring schedules behave like independent queued items, not like a single mutable timer
The current due task is deleted from the queue during processing.
That means:
- there is no long-lived "same task instance" for a recurring series
- each recurrence becomes a new queued task record
The scheduler runs the automation with:
- the application context
- the unserialized
args payload from the task
This is why scheduled automations can behave differently per task even when the underlying automation definition is the same.
Jetstack exposes two practical ways to trigger scheduler processing.
The scheduler page includes a manual run action.
Use it when:
- testing a new scheduled setup
- processing due tasks immediately during administration
- verifying that a due automation behaves as expected
This action runs the scheduler up to the current moment.
The scheduler presenter also exposes a route used by the tenant background process. Its purpose is broader than only the scheduler itself.
In addition to scheduled tasks, that run also processes:
- due async automation timeouts
- async upload housekeeping
- cache cleanup
For documentation purposes, the important point is this:
- the scheduler is part of the platform's operational background cycle, not an isolated utility page
¶ Hidden And Internal Fields Worth Knowing
Most implementers only need the visible scheduler inputs, but a few internal fields are useful to understand.
Every scheduled task gets a UUID in addition to the numeric ID.
Why it matters:
- UI actions such as skip, cancel, and logging toggles can target the task by UUID
- integrations or tooling may prefer UUID-based references
The scheduler table can also contain an internal schedule_definition_id used by implementation synchronization.
Why it matters:
- not every scheduled task is purely ad hoc
- some recurring scheduled records may be linked to synchronized implementation-level schedule definitions
For most tenant builders, this is background infrastructure rather than a field to configure directly in the scheduler page.
Configure:
automation = target automation
run_at = desired future time
next_run = empty
last_run = empty
Use this for:
- reminders
- delayed notifications
- future follow-up checks
Configure:
run_at = first planned daily run
next_run = +1 day
last_run = empty or set to an end date
Use this for:
- daily sync
- morning reports
- recurring housekeeping
Configure:
run_at = first send time
next_run = recurrence step
last_run = final allowed boundary
Use this for:
- temporary campaigns
- time-boxed reminders
- limited retry windows
Configure through automation or API:
- select automation
- set
args
- set
run_at
- optionally set recurrence and log choice
Use this when:
- the scheduled automation needs object-specific or case-specific input
- Should this happen immediately, or is delayed execution actually safer?
- Does the target automation require explicit arguments?
- Should this be a one-time delay or a recurring schedule?
- Should the schedule stop automatically at a boundary?
- Is logging important enough to justify the extra operational data?
- If one occurrence is not needed, do you want to skip just that run or cancel the queued task entirely?
- Use scheduled automations that are stable without UI context.
- Keep
next_run expressions simple and readable.
- Use
last_run for finite schedules instead of relying only on manual cancellation.
- Turn on
log_runs for business-critical jobs.
- Use skip for one missed occurrence and cancel for removing the queued task itself.
- Prefer programmatic scheduling when the automation needs argument payload.