Skip to content

Function schedules

A function schedule binds a CRON expression and a time zone to a published global function so it runs on a recurring cadence with no user in the loop. The schedule itself contains no code — the logic is a global function with the job contract, authored in C# in the workspace Net Operation Project. Schedules are managed on the Function Schedules page (Constructor area, group Automation & logic) and through the Configuration API.

  • Target function — a published global function with the job contract. Functions with other contracts are rejected as schedule targets.
  • CRON expression — standard five-field CRON syntax (minute, hour, day of month, month, day of week).
  • Time zone — optional time zone identifier. When empty, the schedule inherits the workspace time zone. Occurrence times are computed in the effective zone.
  • Arguments — an optional JSON payload passed to the function on every occurrence.
  • StatusEnabled or Disabled. A disabled schedule enqueues nothing.
  • Timeout — the maximum duration of one occurrence. Defaults to 60 seconds, configurable up to 86400. The value is captured onto each queued occurrence when it is enqueued.

The worker computes the next occurrence from the CRON expression and the effective time zone. Each due occurrence is enqueued as a background job and executed by the worker:

  • Runs execute under the built-in system automation actor, not under the administrator who created the schedule.
  • Claiming due work is concurrency-safe: concurrent workers never execute the same occurrence twice.
  • Schedules use target-function active-work deduplication: a new occurrence is skipped while any job for the target function is still queued or running, including work started through a manual or API enqueue. A slow run therefore never stacks up behind itself and a schedule never overlaps another active invocation of its target.
  • The skipped occurrence is stored as a separate Skipped run with its own schedule correlation. It is not linked as the result of the active job and cannot complete, cancel, recover, or otherwise change that job.
  • Every occurrence is visible in run history.

The schedule list shows the operational state of each schedule: next planned run, last activity timestamp, last status, and last error.

For machine-readable discovery, join the schedule’s BusinessFunctionId to GET /api/workspace/admin/function-catalog. Its active CurrentPublishedContract must be Job. Status, TargetState, and NextRunAt describe whether a future occurrence can be queued; jobs with Source=Schedule and the same ScheduleId prove actual enqueue and execution.

When the target function no longer resolves to a runnable published function (for example, it was unpublished or removed), the schedule is marked broken with a target error and a broken-at timestamp, and it cannot execute. Saving the schedule with a valid target resets it to the ready state.

To run the target function once, launch it from the Function Catalog page (Constructor area, group Automation & logic) instead of editing the schedule. A manual run does not modify the schedule or its next planned occurrence, and it appears in run history like any other run.

Schedules are plain CRUD resources in the Configuration API:

GET /api/workspace/admin/function-schedules
POST /api/workspace/admin/function-schedules
GET /api/workspace/admin/function-schedules/{scheduleId}
PUT /api/workspace/admin/function-schedules/{scheduleId}
DELETE /api/workspace/admin/function-schedules/{scheduleId}

A create payload:

{
"Name": "Nightly SLA sweep",
"BusinessFunctionId": "<function-id>",
"TimeZone": "Europe/Berlin",
"CronExpression": "0 3 * * *",
"Args": { "BatchSize": 200 },
"Status": 1,
"TimeoutSeconds": 300
}

Status is numeric in JSON: 0 = Disabled, 1 = Enabled. Updates go through PUT and send the RowVersion last read; a stale value is rejected as a conflict instead of overwriting a concurrent change. Create and update validate the CRON expression, the time zone identifier, the timeout range, and that the target function exists and is a published global job function.

After enabling a schedule, verify NextRunAt. For each due time, expect either one newly queued job or one diagnostic Skipped run when the target function already has active work. Do not treat Skipped as a failed active job and do not compensate by submitting a manual duplicate.