Skip to main content

Schedules

View Markdown

A Schedule starts a Workflow Execution at times you define: on an interval, on a calendar expression, or on a combination of both.

A Schedule is its own object in the Temporal Service with its own Id, separate from the Workflow Executions it starts. You can update, pause, backfill, or trigger it without changing or redeploying the Workflow code it runs.

That separation is what you get instead of running a scheduler alongside your application. There's no second system to deploy, monitor, and reconcile with your Workers, and every start the Schedule makes is an ordinary Workflow Execution with the same durability, retries, and Event History as one you start by hand.

What a Schedule controls

  • Spec. When Actions happen: an interval (45m, or 6h/5h for every six hours offset into the fifth hour) or a calendar expression, given as a cron string (0 8 * * 1-5, weekdays at 8:00 UTC) or as JSON with named fields ({"dayOfMonth": "1,15", "hour": "11-14"}). One Spec can combine several of each and add start and end times, exclusions, jitter, and a time zone. Exclusions and embedded time zone data are available through the SDKs and API, but not the CLI or Web UI.
  • Overlap Policy. What happens when it's time to start and the previous Execution is still running: Skip (the default), BufferOne, BufferAll, CancelOther, TerminateOther, or AllowAll.
  • Catchup Window. Which missed Actions to take when the Temporal Service was unavailable at the scheduled time. The default is one year; the minimum is ten seconds.
  • Pause-on-failure. Pause the Schedule automatically when a scheduled Execution ends in failure or timeout.
  • Backfill. Run every Action for a past time range now, including a range from before the Schedule existed.
  • Action limit. Stop after a set number of scheduled Actions, after which the Schedule behaves as paused.

Every Execution a Schedule starts carries the TemporalScheduledStartTime and TemporalScheduledById Search Attributes, so you can query scheduled runs with a List Filter the same way you query anything else.

What a Schedule doesn't do

  • Pausing a Schedule doesn't pause what's already running. It stops future Actions. Executions the Schedule already started keep going.
  • A Paused Workflow Execution still counts as running. When the Schedule evaluates its Overlap Policy, a Paused Execution is an open Execution, so Skip skips and BufferOne buffers behind it. See Interaction with Workflow Pause.
  • Listing Schedules is eventually consistent. ListSchedules and CountSchedules are served by Visibility and share its rate limit, so a Schedule you just created or deleted may not appear right away.

How to choose between a Schedule, a Cron Job, and Start Delay

  • Use a Schedule when the same Workflow has to run more than once. It's the right choice as soon as you need to pause the series during an incident, change the timing without a deploy, or run the Actions an outage skipped. Use it for new applications even when the timing is a plain cron expression, because you get those controls whether or not you need them yet.
  • Use Start Delay when there's exactly one run, at a time you know when you start it. A trial expiry, a cancellation deadline, a reminder. It isn't recurring, and it's incompatible with both Schedules and Cron Jobs, so it's not a way to hold off the first Action of a Schedule. Set a start time on the Schedule Spec for that.
  • Keep a Temporal Cron Job if you have one running, but don't write new ones. A cron string is a property of the Workflow Execution rather than a separate object, so the next Run starts only after the current one closes, and changing or stopping the series means terminating the Workflow. A Schedule covers the same cases and lets you update it in place.

If the waiting happens inside a Workflow that's already running, none of these apply. Use a Timer.

Resources

Or jump straight to the SDK feature guide for implementation details: