Four TemporalSchedule resources that exercise the different trigger styles and
options the CRD supports. Each schedule is its own file; they share a cluster and
namespace defined in 00-shared.yaml.
| File | Trigger | Highlights |
|---|---|---|
00-shared.yaml | — | Shared TemporalCluster (app) + TemporalNamespace (scheduling). Apply first. |
nightly-report.yaml | Cron (0 2 * * *, NY time) | args, retryPolicy, memo, overlapPolicy: Skip, pauseOnFailure |
healthcheck-every-15m.yaml | Interval (every: 15m, offset: 2m) | jitter |
business-hours-sync.yaml | Structured calendar | weekdays 09:00–17:00 hourly, no cron syntax |
maintenance-window.yaml | Cron (Sundays 03:00) | starts paused: true |
All four schedules set allowDeletion: true, so deleting the CR also deletes the
schedule in Temporal. Set it to false (the default) to leave the schedule in
place when the CR is removed.
Apply #
Apply the shared cluster + namespace first, then any subset of schedules:
kubectl apply -f 00-shared.yaml
kubectl apply -f nightly-report.yaml
# ...or apply everything in the directory at once (00-shared sorts first):
kubectl apply -f .
kubectl get temporalschedules # short name: tsch
kubectl describe tsch nightly-report
The printed READY column reflects the Ready condition; PAUSED reflects the
live schedule state.
Prerequisites for workflows to actually run #
Creating a TemporalSchedule registers the schedule with Temporal, but a fired
action only makes progress when:
- The referenced
TemporalClusterisReady. - The target Temporal namespace exists. The operator does not auto-create
namespaces, so
00-shared.yamlregisters one (scheduling) via aTemporalNamespace. - A worker is polling the schedule’s
taskQueuefor the namedworkflowType. Without a worker the schedules still appear in the Temporal UI andtemporal schedule list; they just won’t execute.
To reuse an existing cluster/namespace, skip 00-shared.yaml and update
clusterRef.name / namespace in each schedule file to match your environment.
Try it #
# Pause / resume in place by editing state.paused, then re-apply:
kubectl patch tsch healthcheck-every-15m --type merge \
-p '{"spec":{"state":{"paused":true}}}'
# Inspect from inside the cluster with the Temporal CLI:
temporal schedule list --namespace scheduling --address <frontend>:7233
temporal schedule describe --schedule-id nightly-report --namespace scheduling
Manifests #
00-shared.yaml #
# Shared prerequisites for the schedule examples in this directory.
#
# Every schedule here points at this cluster (clusterRef.name: app) and runs in
# this namespace (namespace: scheduling). Apply this file first, then any of the
# per-schedule files.
#
# Reusing an existing cluster/namespace? Skip this file and update clusterRef /
# namespace in the schedule files to match your environment. The operator does
# NOT auto-create Temporal namespaces, so the namespace must be registered by a
# TemporalNamespace before a schedule can use it.
---
apiVersion: temporal.bmor10.com/v1alpha1
kind: TemporalCluster
metadata:
name: app
spec:
version: "1.31.1"
numHistoryShards: 512
persistence:
defaultStore:
sql: { pluginName: postgres12, host: postgres.default.svc, port: 5432, database: temporal, user: temporal, passwordSecretRef: { name: temporal-store, key: password } }
visibilityStore:
sql: { pluginName: postgres12, host: postgres.default.svc, port: 5432, database: temporal_visibility, user: temporal, passwordSecretRef: { name: temporal-store, key: password } }
---
apiVersion: temporal.bmor10.com/v1alpha1
kind: TemporalNamespace
metadata:
name: scheduling
spec:
clusterRef: { name: app }
retentionPeriod: "168h"
description: "Namespace for schedule examples"
business-hours-sync.yaml #
# Structured calendar: weekdays, every hour from 09:00-17:00 (UTC).
# Field-level control without cron syntax. Ranges are inclusive [start,end].
#
# Requires 00-shared.yaml (cluster "app" + namespace "scheduling").
apiVersion: temporal.bmor10.com/v1alpha1
kind: TemporalSchedule
metadata:
name: business-hours-sync
spec:
clusterRef: { name: app }
namespace: scheduling
allowDeletion: true
schedule:
timezoneName: "UTC"
structuredCalendar:
- comment: "hourly on the hour, weekdays 9-17"
hour:
- { start: 9, end: 17 }
minute:
- { start: 0, end: 0 }
dayOfWeek:
- { start: 1, end: 5 } # Mon(1)..Fri(5); 0 and 7 are Sunday
action:
startWorkflow:
workflowType: SyncInventory
taskQueue: inventory
healthcheck-every-15m.yaml #
# Interval schedule: every 15 minutes (with a 2m phase offset) and jitter.
#
# Requires 00-shared.yaml (cluster "app" + namespace "scheduling").
apiVersion: temporal.bmor10.com/v1alpha1
kind: TemporalSchedule
metadata:
name: healthcheck-every-15m
spec:
clusterRef: { name: app }
namespace: scheduling
allowDeletion: true
schedule:
intervals:
- every: "15m"
offset: "2m"
jitter: "30s" # randomize each fire time by 0..30s
action:
startWorkflow:
workflowType: Healthcheck
taskQueue: ops
maintenance-window.yaml #
# Paused schedule: created but not firing. Flip state.paused to false and
# re-apply to resume; the operator reconciles pause/unpause in place.
#
# Requires 00-shared.yaml (cluster "app" + namespace "scheduling").
apiVersion: temporal.bmor10.com/v1alpha1
kind: TemporalSchedule
metadata:
name: maintenance-window
spec:
clusterRef: { name: app }
namespace: scheduling
allowDeletion: true
schedule:
calendars:
- "0 3 * * 0" # Sundays at 03:00
action:
startWorkflow:
workflowType: RunMaintenance
taskQueue: ops
state:
paused: true
notes: "paused until the next maintenance window is approved"
nightly-report.yaml #
# Calendar (cron) schedule: nightly at 02:00 New York time.
# Exercises args, a retry policy, a memo, an overlap policy, and allowDeletion.
#
# Requires 00-shared.yaml (cluster "app" + namespace "scheduling").
apiVersion: temporal.bmor10.com/v1alpha1
kind: TemporalSchedule
metadata:
name: nightly-report
spec:
clusterRef: { name: app }
namespace: scheduling
allowDeletion: true # let the operator delete the schedule with the CR
schedule:
timezoneName: "America/New_York"
calendars:
- "0 2 * * *" # standard 5-field cron; also supports @daily etc.
action:
startWorkflow:
workflowType: GenerateReport
taskQueue: reports
workflowID: nightly-report # optional; defaults to a generated ID
# Args are raw JSON payloads (one json/plain payload per list item).
args:
- { "scope": "daily", "limit": 1000 }
- "us-east"
workflowExecutionTimeout: "1h"
retryPolicy:
initialInterval: "10s"
backoffCoefficient: "2.0" # decimal string
maximumInterval: "5m"
maximumAttempts: 5
memo:
owner: { "team": "analytics" }
policies:
overlapPolicy: Skip # Skip;BufferOne;BufferAll;CancelOther;TerminateOther;AllowAll
catchupWindow: "1h"
pauseOnFailure: true