Task Schedules
User-defined task schedules let operators automate recurring or one-shot operations (power control, firmware upgrade, bring-up, ingest) against a persistent set of rack targets, without requiring an external scheduler.
Concepts
A schedule contains timing, an operation template, an overlap policy, and a persistent scope. Each scope entry selects a rack and optional component filter, and records its last submitted task. The dispatcher submits a task for each eligible scope when the schedule fires.
Schedule Types
The spec_type field selects the scheduling mechanism. The spec field
carries a type-specific string.
Interval
next_run_at is set to now + duration when the schedule is created or
resumed. After a firing or overlap skip, the next time is the dispatch time plus the interval. Missed intervals are not replayed. The duration must be positive.
Cron
next_run_at is computed by evaluating the cron expression in the schedule’s
IANA timezone (default "UTC"). The timezone only affects cron: interval and
one-time specs are always absolute.
Timezone format
Use UTC or an IANA location such as America/Los_Angeles, Europe/London, or Asia/Tokyo. Flow resolves names through Go’s timezone database; availability of aliases such as EST depends on that database. Use full location names for portable configuration. An unresolvable cron timezone is rejected. The timezone is not used to interpret interval or one-time specs.
One-Time
Becomes due at the specified RFC 3339 timestamp, including its explicit offset. Dispatch normalizes it to UTC. A timestamp in the past is due on the next poll. After firing, enabled is
set to false and next_run_at is cleared. A consumed one-time schedule
cannot be re-armed (create a new one instead).
Overlap Policy
Controls what happens when a schedule fires while the previous task for the same scope is still active (waiting, pending, or running).
The overlap check is per-scope: a schedule with five rack targets can fire on four racks while skipping the one whose previous task is still running.
The policy is not consulted for manual triggers (TriggerTaskSchedule):
all scopes are submitted unconditionally.
Scope and Component Filters
A schedule’s scope is the set of racks it targets. Each scope entry targets one rack, with an optional
component_filter that restricts which components in that rack are included.
Component filter variants
These JSON forms describe the stored scope filter. RPC requests use the typed target_spec and component-filter messages from the gRPC reference.
Scope management RPCs
Four RPCs manage scope after a schedule is created:
Filter merge rules (AddTaskScheduleScope only)
When the incoming rack already has a scope entry, the existing and incoming
component_filter values are merged according to these rules:
If a merge error occurs for any rack, the entire AddTaskScheduleScope
request fails and no changes are persisted. To change the kind of filter on
an existing scope entry, use UpdateTaskScheduleScope (which replaces rather
than merges) or remove the scope entry first.
For component-level targets (specific component UUIDs), the server resolves which rack each component belongs to and groups them into per-rack scope entries automatically.
API Reference
All RPCs live in the Flow gRPC service.
Schedule lifecycle
Scope management
Advisory
CreateTaskSchedule
Creates a schedule and its initial scope in a single transaction.
Required fields:
Optional fields:
The initial scope is derived from the operation’s target_spec. Use the scope
management RPCs to modify it after creation.
UpdateTaskSchedule
Updates the scheduling config of an existing schedule. update_mask is
required and controls which fields are written.
Renaming a schedule to another schedule’s name fails the database uniqueness
constraint and returns gRPC UNKNOWN. The update is rejected without changing
the schedule, including other fields supplied in the same request.
The operation itself (what the schedule runs) and scope (which racks it targets)
cannot be changed via UpdateTaskSchedule. To change the operation, delete the
schedule and create a new one. To change the scope, use the scope management
RPCs.
PauseTaskSchedule / ResumeTaskSchedule
Pause sets enabled = false. The schedule will not fire until resumed.
Calling pause on an already-paused schedule is a no-op. Pausing a one-time
schedule that has already fired returns an error (nothing to pause).
Resume sets enabled = true. For interval and cron schedules next_run_at
is recomputed from the current time so the schedule does not fire immediately
if next_run_at is still in the past from before the pause. For a one-time
schedule that was paused before firing, next_run_at is left unchanged.
Resuming a one-time schedule that has already fired (no next_run_at) returns
an error.
TriggerTaskSchedule
Fires the schedule immediately, regardless of next_run_at or enabled state.
All scopes are submitted unconditionally (the overlap policy is ignored).
After firing:
last_run_atis set on the schedule.- For interval/cron schedules,
next_run_atadvances normally. - For one-time schedules,
enabledis set tofalseandnext_run_atis cleared (consumed).
Returns an error if called on a one-time schedule that has already fired.
DeleteTaskSchedule
Deletes the schedule and all its scope entries. In-flight tasks are not cancelled.
ListTaskSchedules
Returns schedules ordered by created_at ascending.
The response includes total: the count before pagination is applied.
Dispatch and failure behavior
Automatic dispatch polls for due schedules every 10 seconds by default. This is a polling interval, not a guaranteed execution deadline.
Flow advances the schedule before submitting tasks. A failed submission for one scope does not prevent other scopes from being submitted, and the same tick is not automatically retried. A one-time schedule is consumed even if all scopes are skipped by overlap policy or task submission fails. Check the resulting tasks rather than treating last_run_at as proof that the hardware operation succeeded.
Pausing or deleting a schedule does not cancel tasks already submitted. Use task controls to manage those tasks separately.
Conflict Checks
CheckScheduleConflicts is an advisory RPC that checks whether a proposed
scheduled operation would overlap with any existing enabled schedule on the
same racks. It returns the conflicting schedules (if any) but does not
block creation.
The check is coarse by design. It compares only the operation type and code; it does not intersect component-type filters or explicit component UUID lists. Two schedules that target entirely disjoint component sets on the same rack will still be reported as conflicting. Treat a non-empty response as a signal for human review, not a guarantee that tasks will collide at runtime. Execution-time conflict detection (the task manager’s conflict rules) remains the authoritative backstop.