Schedule recurring and future work
Register Cron, Interval, and Once schedules, inspect run history, and choose catch-up and overlap behavior.
A schedule stores a pipeline definition and the rule for when to create a run. Every firing creates an ordinary pipeline, so scheduled work uses the same handlers, leases, retries, logs, and dashboard as other work.
Before registering
You need an application API key, a running Pipelogiq orchestration worker, and an application worker that implements the definition's handlers. Automatic ticks are recorded as Skipped with NoWorker when no live application worker is registered. Registering a schedule does not deploy handler code.
Worker availability is checked for the application. It does not prove that every required handler is registered, so verify handler names as well as worker health.
Create or update a schedule
This example assumes your application implements DispatchDueEmailsHandler. Set PIPELOGIQ_API_KEY to its application key, then run:
curl --fail-with-body -i -X PUT http://localhost:8081/schedules/dispatch-due-emails \
-H "X-API-Key: $PIPELOGIQ_API_KEY" \
-H 'Content-Type: application/json' \
--data-binary @- <<'JSON'
{
"kind": "Cron",
"cronExpression": "*/5 * * * *",
"timeZone": "UTC",
"overlapPolicy": "Skip",
"catchupPolicy": "None",
"catchupMax": 10,
"jitterSeconds": 0,
"definition": {
"name": "dispatch-due-emails",
"stages": [
{ "stageName": "dispatch", "stageHandlerName": "DispatchDueEmailsHandler", "input": "{\"batchSize\":100,\"scheduledFor\":\"{{scheduledFor}}\"}" }
]
}
}
JSONThe schedule name is case-insensitive and scoped to the application. A new schedule returns 201. An unchanged repeat returns 200 without moving nextRunAt or increasing its definition version. A meaningful change updates the version and replans the next run. Applying a definition to an archived schedule activates it again.
Keep the source definition with your application. Read responses redact sensitive values; do not use a redacted response as the authoritative body for an update.
Choose a trigger
| Kind | Required fields | Behavior |
|---|---|---|
Cron | cronExpression, optional timeZone | Five-field cron; descriptors such as @hourly are accepted. Six-field seconds syntax is not supported. |
Interval | intervalSeconds | At least 10 seconds between planned ticks. |
Once | Future runAt timestamp | Fires at one RFC3339 timestamp and then archives. |
Use an IANA time zone such as Europe/Tallinn for local-time cron behavior; omitted time zone means UTC. A nonexistent spring-forward local time is skipped, and a repeated autumn local time can fire twice. Choose UTC when that distinction would be surprising for the business task.
The scheduler normally polls once per second. Execution can occur later because of load and worker capacity. Use recorded lag instead of treating the schedule as a real-time deadline guarantee.
Overlap and catch-up
When a previous scheduled run remains unfinished:
- Skip: consume the tick without creating another pipeline. This is the default.
- Allow: create another run even while the previous one is active. Handlers must tolerate concurrent work.
- Replace: cancel the previous run and create another. Cancellation is cooperative and cannot undo external actions already started.
- Queue: available in the API/UI, but strict serialization is not a verified guarantee for this release. Use Skip for a workload that must avoid overlapping runs, and make each run resume outstanding business work.
Catch-up controls missed ticks while the scheduler was unavailable:
| Policy | What runs |
|---|---|
None | The latest missed tick; earlier enumerated ticks are recorded as skipped. |
One | The latest missed tick, labelled as a Catchup run. |
All | Up to catchupMax missed ticks, oldest first; later excess ticks are skipped. |
Missed-tick enumeration is bounded at 1,000. Do not use schedule history as an unlimited replay engine for a long outage. If business data must be processed without gaps, make handlers query the durable business backlog.
jitterSeconds offsets firing to spread load. It does not change the recorded planned tick. The normal zero-jitter example above is easier to inspect while learning.
Read history and run manually
curl --fail-with-body http://localhost:8081/schedules/dispatch-due-emails \
-H "X-API-Key: $PIPELOGIQ_API_KEY"
curl --fail-with-body http://localhost:8081/schedules/dispatch-due-emails/runs \
-H "X-API-Key: $PIPELOGIQ_API_KEY"Run rows identify scheduledFor, firedAt, lag, trigger, outcome, definition version, and pipeline ID when a run was created. Created means a pipeline was created, not that its business work succeeded. Follow the pipeline link to inspect its final status.
A manual run does not advance the schedule cursor and does not apply automatic overlap/catch-up decisions. The optional input replaces the first stage's input:
curl --fail-with-body -X POST http://localhost:8081/schedules/dispatch-due-emails/trigger \
-H "X-API-Key: $PIPELOGIQ_API_KEY" \
-H 'Content-Type: application/json' \
-d '{"input":{"batchSize":1}}'Dashboard Operators and Admins can use Run now, pause, resume, and archive. Viewers can inspect schedules and runs. Resuming plans from the current time; it does not replay every tick during an intentional pause.
Definition placeholders
Only stage input and pipeline context values substitute these placeholders:
| Placeholder | Value |
|---|---|
{{scheduledFor}} | Planned tick in UTC RFC3339 format. |
{{runId}} | Schedule run ID. |
{{previousPipelineId}} | Last pipeline created by this schedule, or empty for the first run. |
Pipeline names, stage/handler names, and keywords are not templated. There is no general template language or dependency between schedules. Build related steps into one pipeline or coordinate them in your application.