Insights & updates from our experts
Overview
Runs runbooks on a recurring or one-off schedule. The connector exposes two triggers — Scheduler for runbooks whose schedule is configured statically on the trigger, and Dynamic Scheduler for runbooks whose schedules are created, updated, and deleted at runtime by other runbooks — plus three actions (Create Schedule, Update Schedule, Delete Schedule) that manage schedules pointing at Dynamic Scheduler runbooks. Schedules are persisted in iPaaS and dispatched by the platform's internal scheduler service; no external service is called.
Prerequisites
- Access to the Xurrent runbook builder.
- For Dynamic Scheduler workflows, the runbook being scheduled must already exist in the same solution and use the Dynamic Scheduler trigger; the manager runbook references it by
runbook_uuid.
Authentication
None — this connector runs in-process against the current solution's schedule store. No connection needs to be configured.
Triggers
Scheduler
Triggers the runbook on the recurrence configured on the trigger itself. When the runbook is provisioned, a schedule record is created from the trigger config; when the runbook is deprovisioned, the schedule is soft-deleted. The trigger is internal — the dispatch is performed by the platform's scheduler service, not by an external HTTP caller.
Use case: run a runbook every 15 minutes, every weekday at 09:00, on the first of every month, etc., where the cadence is known at design time and lives with the runbook.
Input Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
schedule |
Recurrence | Yes | - | Recurrence definition for the runbook. See Schedule (Recurrence) object fields below. |
request_body |
Hash | No | - | Optional JSON body merged into the request that fires the runbook. Surfaces under body on each run alongside the platform-injected schedule_reference. |
Schedule (Recurrence) object fields
| Field | Type | Required | Description |
|---|---|---|---|
frequency |
String | Yes | One of no_repeat, minutely, hourly, daily, weekly, monthly, yearly. |
disabled |
Boolean | No | When true, the schedule is paused — no occurrences fire until it is re-enabled. The reference is preserved. |
interval |
Integer | When frequency != no_repeat |
Cadence multiplier. >= 1. E.g. frequency: weekly, interval: 2 runs every two weeks. |
time_zone |
String | When frequency != no_repeat |
IANA time zone name (e.g. "UTC", "Europe/Amsterdam"). |
time_of_day |
String / Time | When frequency is daily, weekly, monthly, or yearly |
Local time the schedule fires (e.g. "09:00:00"). Interpreted in time_zone. Optional for minutely/hourly (defaults to current time). |
start_date |
Date | No | First eligible day for the schedule. Defaults to today when frequency != no_repeat. |
end_date |
Date | No | Last eligible day. The schedule disables itself once the next occurrence would fall after end_date. Must be >= start_date. |
day |
Array of String | When frequency = weekly |
Weekday names (monday…sunday) the schedule fires on. |
day_of_week |
Boolean | No | For monthly / yearly: when true, switches the field set to day_of_week_index + day_of_week_day; when false, uses day_of_month. |
day_of_month |
Array of Integer | When frequency = monthly and day_of_week = false |
1–31, or -1 for the last day of the month. |
day_of_week_index / day_of_week_day |
Integer / String | When frequency is monthly or yearly and day_of_week = true |
E.g. index: 2, day: "tuesday" for the second Tuesday. index accepts 1, 2, 3, 4, or -1 (last). |
month_of_year |
Array of Integer | When frequency = yearly |
1–12. |
Example Input
Trigger configuration on the runbook (every other week on Saturday and Sunday at 16:55:50 UTC):
{
"schedule": {
"frequency": "weekly",
"time_zone": "UTC",
"interval": 2,
"day": ["saturday", "sunday"],
"time_of_day": "16:55:50"
},
"request_body": { "source": "scheduler" }
}
Output
| Field | Type | Required | Description |
|---|---|---|---|
body |
Hash | No | The request body the scheduler dispatched to the runbook. Includes the platform-injected schedule_reference and any keys from request_body on the trigger config. |
triggered_at |
DateTime | Yes | UTC timestamp the runbook was dispatched. |
Example Output
{
"body": {
"schedule_reference": "f0b5a7e9-3c52-4e7a-9b2e-2a9c1b1d6e44",
"source": "scheduler"
},
"triggered_at": "2026-04-29T16:55:50Z"
}
Error Handling
- Provision failure — if the schedule cannot be persisted (validation error on the recurrence, missing required fields, invalid
frequency, etc.), provision raisesFailed to register schedule: <error>and the runbook deployment fails. - Deprovision — silently no-ops if no
schedule_referenceis stored against the trigger; otherwise performs a soft delete (deleted: true). - Invalid recurrence at runtime — if
next_occurrence_atcannot be computed (e.g. timeout while computing), the schedule disables itself and the next-occurrence error is recorded on the schedule record. - Dispatch failure — if dispatching the runbook returns a non-2xx response, the platform's scheduler service records
Runbook execution failed with status <status>and continues to the next occurrence.
Best Practices
- Use this trigger when the cadence is owned by the runbook itself. For schedules driven by another runbook (e.g. one schedule per onboarded customer), use Dynamic Scheduler plus Create Schedule.
- Set a
time_zoneexplicitly. Defaults to the server'sTime.zone, which is rarely what users expect when reasoning about local fire times. - Put run-correlation data (e.g. a tenant ID, environment marker) into
request_body; the scheduler reference is injected for free asschedule_reference.
Dynamic Scheduler
Triggers a runbook when an external Create Schedule action fires its scheduled job. Unlike Scheduler, this trigger has no recurrence config of its own — the schedule lives in a separate record created by another runbook calling Create Schedule, and the trigger only describes how to extract a job-context identifier from the inbound request.
Use case: run-per-tenant or run-per-resource schedules where the set of schedules changes at runtime — e.g. a manager runbook that creates one schedule per customer onboarded, and a worker runbook (this trigger) that fires when each schedule occurrence dispatches.
Input Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
job_context_identifier_path |
String | No | - | Dot-path into the inbound request used to derive the runbook's job-context identifier — e.g. "body.tenant_id" or "schedule_reference". The path is resolved against { body: <parsed JSON>, triggered_at: <DateTime> }; if the first segment is not a top-level key on that object, body is prepended. Resolution failures are logged and the run continues without a context identifier. Optional / hidden by default. |
Example Input
Trigger configuration on the runbook:
{
"job_context_identifier_path": "body.schedule_reference"
}
Output
| Field | Type | Required | Description |
|---|---|---|---|
body |
Hash | No | The request body the scheduler dispatched (includes schedule_reference plus any request_body set on the originating Create Schedule action). |
triggered_at |
DateTime | Yes | UTC timestamp the runbook was dispatched. |
Example Output
{
"body": {
"schedule_reference": "tenant-42-daily",
"tenant_id": "42"
},
"triggered_at": "2026-04-29T09:00:00Z"
}
Error Handling
- Path not present — the path resolver walks
bodyfirst and falls back to top-level keys; if no key matches, no context identifier is set and the run proceeds normally. - Path traversal error — if a segment is applied to a non-hash value (e.g. indexing into an array with a string key), the trigger logs
Unable to determine job context identifier. <ErrorClass>: <message>and the run proceeds without a context identifier. - Empty body — the trigger accepts empty bodies;
bodyis set to the raw value (nilor empty string) andtriggered_atis still emitted.
Best Practices
- Set
job_context_identifier_pathto a value that uniquely identifies the work item driven by the schedule (e.g.body.schedule_referenceorbody.tenant_id); job-context identifiers are how iPaaS deduplicates and correlates concurrent runs. - Keep the path stable. Changing it after schedules are live retroactively changes how concurrent runs of the same worker are correlated.
- When the manager runbook owns the lifecycle, store
schedule_referencesomewhere durable (a runbook variable, a CMDB record) so that Update Schedule and Delete Schedule can be called against it later.
Actions
Create Schedule
Creates a new schedule that fires the runbook identified by runbook_uuid. The target runbook must be in the same solution and must use the Dynamic Scheduler trigger (the platform rejects the call otherwise). On success the action returns the schedule_reference (echoed from the input) and the computed next_occurrence_at.
Use case: a manager runbook that creates per-tenant or per-resource schedules at runtime — for example, when a new customer is onboarded, create a daily schedule that runs the worker runbook for that customer.
Input Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
runbook_uuid |
String | Yes | - | UUID of the worker runbook to schedule. Must use the Dynamic Scheduler trigger and live in the same solution. |
schedule_reference |
String | Yes | - | Caller-supplied identifier for the schedule, unique per solution. Use this same value to Update Schedule or Delete Schedule later. |
schedule |
Recurrence | Yes | - | Recurrence definition. Same fields as documented under the Scheduler trigger's Schedule (Recurrence) object fields. |
request_body |
Hash | No | - | Optional JSON merged into the request body the scheduler dispatches. Available on the worker runbook's body output alongside schedule_reference. |
Example Input
{
"runbook_uuid": "7c0d8739-5fbd-4a6f-a1b4-2991bb0e2b54",
"schedule_reference": "tenant-42-daily",
"schedule": {
"frequency": "weekly",
"time_zone": "UTC",
"interval": 1,
"day": ["monday", "wednesday", "friday"],
"time_of_day": "09:00:00"
},
"request_body": { "tenant_id": "42" }
}
Output
| Field | Type | Required | Description |
|---|---|---|---|
schedule_reference |
String | Yes | Echo of the input schedule_reference. Use this to drive subsequent Update Schedule / Delete Schedule calls. |
next_occurrence_at |
DateTime | No | UTC timestamp of the next computed firing. null if the schedule could not compute one (e.g. end_date is in the past). |
next_occurrence_errors |
String | No | Human-readable message describing why next_occurrence_at is null (e.g. "Timeout Computing next occurrence"). |
Example Output
{
"schedule_reference": "tenant-42-daily",
"next_occurrence_at": "2026-05-01T09:00:00Z",
"next_occurrence_errors": null
}
Error Handling
- Unknown runbook — if
runbook_uuiddoes not match a runbook in the current solution, the action fails the job withFailed to create schedule: No Runbook found. - Wrong trigger — if the target runbook does not use a supported scheduler trigger template, the action fails with
Failed to create schedule: Trigger template <uuid> is not supported for scheduling. - Duplicate reference —
schedule_referencemust be unique per solution; reusing one fails validation withFailed to create schedule: ["Reference must be unique per solution"]. - Invalid recurrence — missing
frequencyfor a recurrent schedule,interval < 1, an unknownfrequency, or invalidday_of_week/month_of_yearvalues fail validation with the corresponding ActiveRecord error message.
Best Practices
- Generate
schedule_referencedeterministically from a stable key (e.g."tenant-#{id}-daily") so the manager runbook can recompute it later without persisting it separately. - Capture
next_occurrence_errorsand surface it back to the caller — a successful create with anullnext_occurrence_atmeans the schedule was registered but will never fire as configured. - Pass tenant/resource identifiers through
request_bodyrather than encoding them intoschedule_reference; the worker runbook reads them frombodydirectly.
Update Schedule
Replaces the recurrence on an existing schedule identified by schedule_reference. Pending dispatches enqueued before the update are unscheduled so the new recurrence takes effect immediately.
Use case: change the cadence of a previously created schedule — e.g. shift a customer's nightly run from 02:00 to 04:00 after their time zone changes, or pause a schedule by setting disabled: true on the recurrence.
Input Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
schedule_reference |
String | Yes | - | The schedule_reference returned by Create Schedule. Scoped to the current solution. |
schedule |
Recurrence | Yes | - | New recurrence definition. Treated as a full replacement — frequency-irrelevant fields are cleared (e.g. switching to weekly clears day_of_month), and last_enqueued_for is reset so the new recurrence fires from its own start_date. Same field set as Create Schedule. |
Example Input
{
"schedule_reference": "tenant-42-daily",
"schedule": {
"frequency": "weekly",
"time_zone": "UTC",
"interval": 1,
"day": ["monday", "wednesday", "friday"],
"time_of_day": "09:00:00"
}
}
Output
| Field | Type | Required | Description |
|---|---|---|---|
success |
Boolean | Yes | true when the schedule was updated. The action fails the job before reaching this output if the update could not be applied. |
Example Output
{ "success": true }
Error Handling
- Unknown reference —
schedule_referencenot found in the current solution (or already soft-deleted) fails the job withFailed to update schedule: Schedule not found. - Validation failure — invalid recurrence values fail with
Failed to update schedule: Schedule update failed. Schedule fields not provided inscheduleare reset to their defaults during the update — pass a complete recurrence object, not a partial patch.
Best Practices
- Treat Update Schedule as a full replacement, not a patch. Recompute the entire recurrence from your source of truth before calling.
- To pause a schedule without losing the reference, Update Schedule with
disabled: trueon the recurrence; to resume, send another Update Schedule withdisabled: false. - For one-off changes to the next firing only, prefer creating a fresh schedule with Create Schedule and deleting the old one — Update Schedule clears the queued occurrence and recomputes from the new recurrence's
start_date.
Delete Schedule
Soft-deletes the schedule identified by schedule_reference. Pending dispatches for the schedule are unscheduled.
Use case: tear down per-tenant schedules when a tenant is offboarded; clean up schedules whose owning resource has been removed.
Input Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
schedule_reference |
String | Yes | - | The schedule_reference returned by Create Schedule. Scoped to the current solution. |
Example Input
{ "schedule_reference": "tenant-42-daily" }
Output
| Field | Type | Required | Description |
|---|---|---|---|
success |
Boolean | Yes | Always true when the action returns. Deletion of a non-existent reference is treated as a no-op. |
Example Output
{ "success": true }
Error Handling
Soft-delete is idempotent — calling Delete Schedule with a schedule_reference that does not exist (or is already deleted) returns { "success": true } without error. There are no validation failure modes once schedule_reference is provided.
Best Practices
- Pair Delete Schedule with the same idempotency key your manager runbook uses to Create Schedule, so reruns of the offboarding flow don't fail when the schedule is already gone.
- Soft-deleted schedules are filtered out by the model's default scope (
where(deleted: false)); callers cannot resurrect a deleted reference. To re-enable, Create Schedule again with a fresh recurrence.
Best Practices
- Use the Scheduler trigger when the cadence is owned by the runbook (one runbook → one schedule). Use Dynamic Scheduler + Create / Update / Delete Schedule when schedules are created at runtime (one runbook → many schedules).
- Use deterministic
schedule_referencevalues (e.g."tenant-<id>-<purpose>") so manager runbooks can update or delete schedules without persisting the reference separately. References must be unique per solution. - Always specify
time_zoneexplicitly on recurrences — relying on the platform default makes runbook behaviour environment-dependent. - Carry tenant/resource identifiers through
request_body. The worker runbook receives them on itsbodyoutput alongside the platform-injectedschedule_reference. - Set
job_context_identifier_pathon Dynamic Scheduler to the field that uniquely identifies the work item (typicallybody.schedule_referenceorbody.tenant_id). Job-context identifiers drive concurrency and correlation for runs of the same worker runbook. - Recurrences with
frequency: minutelyorhourlyself-enqueue the next occurrence after each run.daily/weekly/monthly/yearlyare batched by the platform's daily enqueuer; expect the first daily-or-coarser run to be dispatched directly only when its first occurrence falls before tomorrow.
Common Use Cases
- Recurring runbook on a fixed cadence — add the Scheduler trigger to the runbook, set
frequency,interval,time_of_day, andtime_zone, and provision the runbook. The platform creates the schedule automatically. - Per-tenant scheduled work — manager runbook calls Create Schedule with
schedule_reference: "tenant-<id>-<purpose>",runbook_uuidof a worker runbook (using the Dynamic Scheduler trigger), andrequest_bodycarrying the tenant ID. The worker runbook reads the tenant ID frombodyon each fire. - Pause / resume an existing schedule — manager runbook calls Update Schedule with the same
schedule_referenceand a recurrence carryingdisabled: trueto pause; send another Update Schedule withdisabled: falseto resume. - Bulk teardown on offboarding — when a tenant is removed, manager runbook iterates the tenant's known schedule references and calls Delete Schedule for each. Idempotent, so retries are safe.
References
- iCalendar (RFC 5545) — recurrence semantics that the underlying recurrence engine (ice_cube) implements.
- IANA Time Zone Database — source of valid
time_zonevalues.























