Update-With-Start early return pattern
Update-With-Start can be used for early return: begin a new Workflow Execution and synchronously receive a response while the Workflow Execution continues to run to completion. For example, a payment process can be modeled this way to send payment validation results back to the client synchronously while the transaction Workflow continues in the background. Set WorkflowIDConflictPolicy to FAIL and use a unique Update ID for this pattern if you want to assert it does not reuse an existing Workflow.
Update-With-Start is not atomic
Unlike Signal-with-Start, Update-With-Start is not atomic. If the Update cannot be delivered, for example because there is no running Worker available, a new Workflow Execution will still start. The SDKs will retry the Update-With-Start request, but there is no guarantee that the Update will succeed.
Queries are synchronous and work on completed workflows
Queries can be sent from a Temporal Client or the Temporal CLI to a Workflow Execution even if the Workflow has Completed. This call is synchronous and will call into the corresponding Query handler.
Stack Trace Query for debugging
In many SDKs, the Temporal Client exposes a predefined __stack_trace Query that returns the call stack of all threads owned by that Workflow Execution. This is useful for troubleshooting a Workflow Execution in production, for example if a Workflow Execution has been stuck at a state for longer than expected. The __stack_trace Query name does not require special handling in Workflow code and is available only for running Workflow Executions.
Updates must be manually enabled before Temporal v1.25.0
To use the Workflow Update feature in versions prior to v1.25.0, it must be manually enabled. Set the frontend.enableUpdateWorkflowExecution and frontend.enableUpdateWorkflowExecutionAsyncAccepted dynamic config values to true. For example with the Temporal CLI, run: temporal server start-dev --dynamic-config-value frontend.enableUpdateWorkflowExecution=true and temporal server start-dev --dynamic-config-value frontend.enableUpdateWorkflowExecutionAsyncAccepted=true.
Cron Job termination and cancellation behavior
A Temporal Cron Job does not stop spawning Runs until it has been Terminated or until the Workflow Execution Timeout is reached. A Cancellation Request affects only the current Run. Use the Workflow Id in any requests to Cancel or Terminate.
Temporal Cron Job definition
A Temporal Cron Job is the series of Workflow Executions that occur when a Cron Schedule is provided in the call to spawn a Workflow Execution. The documentation recommends using Schedules instead of Cron Jobs, as Schedules provide better developer experience with more configuration options and the ability to update or pause running Schedules.
Cron Job Run behavior and inheritance
Each Workflow Execution within a Cron Job series is considered a Run. Each Run receives the same input parameters as the initial Run and inherits the same Workflow Options as the initial Run.
Cron Job first task backoff calculation
The Temporal Server spawns the first Workflow Execution in the chain of Runs immediately, but calculates and applies a backoff (firstWorkflowTaskBackoff) so that the first Workflow Task does not get placed into a Task Queue until the scheduled time. After each Run completes, fails, or reaches the Workflow Run Timeout, the next run is created immediately with a new firstWorkflowTaskBackoff calculated based on the current Server time and the defined Cron Schedule.
Cron Job spawn timing with retry policies
The Temporal Server spawns the next Run only after the current Run has Completed, Failed, or has reached the Workflow Run Timeout. If a Retry Policy has been provided and a Run Fails or reaches the Workflow Run Timeout, the Run will first be retried per the Retry Policy until the Run Completes or the Retry Policy has been exhausted. If the next Run per the Cron Schedule is due to spawn while the current Run is still Open (including retries), the Server automatically starts the new Run after the current Run completes successfully.
Cron Job lifetime and Workflow Execution Timeout
A Workflow Execution Timeout is used to limit how long a Workflow can be executing (have an Open status), including retries and any usage of Continue As New. The Cron Schedule runs until the Workflow Execution Timeout is reached or the Workflow is terminated.
Cron Schedule UTC default interpretation
Cron Schedules are interpreted in UTC time by default.
Classic Cron Schedule specification format
The classic Cron Schedule specification uses five fields: minute (0-59), hour (0-23), day of the month (1-31), month (1-12), and day of the week (0-6, Sunday to Saturday). For example, '15 8 * * *' causes a Workflow Execution to spawn daily at 8:15 AM UTC.
robfig predefined Cron schedules
Temporal supports robfig/cron predefined schedules: @yearly (or @annually) = 0 0 1 1 *, @monthly = 0 0 1 * *, @weekly = 0 0 * * 0, @daily (or @midnight) = 0 0 * * *, @hourly = 0 * * * *. The @weekly schedule runs once a week at midnight between Saturday and Sunday.
robfig Cron interval syntax
Temporal supports robfig/cron interval syntax using '@every <duration>' format, where duration must be acceptable by time.ParseDuration.
Cron Schedule timezone prefix syntax
You can change the timezone that a Cron Schedule is interpreted in by prefixing the specification with 'CRON_TZ=<timezone>'. For example, 'CRON_TZ=America/New_York 15 8 * * *' spawns a Workflow Execution every day at 8:15 AM New York time. This feature only applies in Temporal 1.15 and up. The documentation recommends specifying Cron Schedules in UTC when possible to avoid complexity and failure modes.
Cron Schedule daylight saving time pitfall
If a Temporal Cron Job is scheduled around the time when daylight saving time (DST) begins or ends, it might run zero, one, or two times in a day. The Cron library does not perform special DST handling. In the US, DST begins at 2 AM: when falling back, the clock goes 1:59 ... 1:00 ... 1:01 ... 1:59 ... 2:00 ... 2:01 AM, so cron jobs in the 1 AM hour fire twice. When springing forward for DST, cron jobs in the 2 AM hour are skipped. In some timezones like Chile and Iran, DST spring forward is at midnight (11:59 PM followed by 1 AM, making 00:00:00 never happen).
Cron Schedule timezone data management
If you manage your own Temporal Service, you are responsible for ensuring it has access to current tzdata files. The official Docker images are built with tzdata installed (provided by Alpine Linux). An upgrade of the Temporal Service may include an update to tzdata files, which may change the meaning of a Cron Schedule. Be aware of upcoming changes to timezone definitions, particularly around daylight saving time start/end dates.
Cron Schedule absolute time fixed at computation
The absolute start time of the next Run is computed and stored in the database when the previous Run completes, and is not recomputed. If a Cron Schedule runs very infrequently and the definition of the timezone changes between runs, the Run might happen at the wrong time. For example, if the government changes DST dates or moves to permanent DST, a previously computed Run time becomes incorrect.
Dynamic Handlers types
Temporal supports Dynamic Handlers for Workflows, Activities, Signals, Queries, and Updates.
Dynamic Handler definition and purpose
Dynamic Handlers are unnamed handlers in Temporal that are invoked if no other statically defined handler with the given name exists. They provide flexibility to handle cases where the names of Workflows, Activities, Signals, or Queries are not known at runtime.
Dynamic Handlers should be used as fallback, not primary approach
Dynamic Handlers should be used judiciously as a fallback mechanism rather than the primary approach. Overusing them can lead to maintainability and debugging issues. Workflows, Activities, Signals, and Queries should be defined statically whenever possible with clear names that indicate their purpose. Dynamic Handlers should be reserved for cases where handler names are not known at compile time and need to be looked up dynamically at runtime. They are meant to handle edge cases and act as a catch-all, not as the main way of invoking logic.
Workflow Stream one per Workflow limit
A Workflow can have at most one stream. The Workflow Id is the address that publishers and subscribers use to connect.
Workflow Stream publishing from Workflow
The Workflow itself appends events synchronously to the in-memory log. Events are immediately available to subscribers on the next poll.
Workflow Stream publishing from Activities and external processes
Activities scheduled by the Workflow use a client that infers the Temporal Client and parent Workflow Id from the Activity context. External processes such as HTTP backends, starters, scripts, and Activities of other Workflows use a client constructed with an explicit Temporal Client and Workflow Id.
Workflow Stream client batching and flushing
Activities and external processes publish through a client-side buffer. The client accumulates events in memory and flushes the buffer as a single Signal on a configurable batch interval with a default of 2 seconds. A single flush batches all events across all topics that have accumulated since the last flush. This amortizes the cost of Signals: instead of one Signal per event, one Signal carries an entire batch.
Workflow Stream force-flush flag
To send a specific event without waiting for the next batch interval, mark the publish with a force-flush flag. The force-flush flag wakes the background flusher immediately. The call returns after appending to the buffer and signaling the flusher; it does not wait for delivery.
Workflow Stream deduplication by publisher Id and sequence number
Each client has a unique publisher Id and a monotonic sequence number. Every batch is tagged with this pair so that a Signal retried by the SDK or the network deduplicates to a single landing in the log.
Workflow Stream topics
A topic is a string label attached to each event when published. Topics are implicit: they are created on first publish, not declared ahead of time. A topic handle binds a name to a type so that publish and subscribe call sites carry the type with them. Subscribers can filter by one or more topic names, or subscribe to all topics on the stream.
Workflow Stream ordering guarantees
Within a single publisher, ordering is guaranteed. Across publishers, events interleave in the order the Workflow receives the Signals.
Workflow Stream subscription mechanism
A subscriber is any process with a Temporal Client that long-polls the Workflow for new events. Each poll is an Update that blocks until events are available past the subscriber's current offset, then returns a batch. The subscriber maintains its own offset. On reconnect, the subscriber resumes from its last offset without coordinating with anyone but the Workflow. Multiple subscribers can attach to the same Workflow concurrently.
Workflow Stream poll response size cap
Poll responses are capped at roughly 1 MB. When a response hits the cap, the subscriber polls again immediately to drain the rest before applying its cooldown.
Workflow Stream cannot subscribe from inside hosting Workflow
Subscribing from inside the Workflow that hosts the stream is not supported. The Workflow processes only the successful return value of each Activity, while the stream may carry partial output from attempts that failed and were retried. Letting the Workflow read its own stream would mix those two views.
Workflow Stream log truncation
Truncation drops entries below a given offset from the in-memory log and from the Continue-As-New payload. It does not remove publish Signals already recorded in Workflow history. A subscriber whose offset falls below the new base after truncation is silently advanced to the current base.
Workflow Stream wire-level handlers
The three handlers registered when constructing a WorkflowStream are: __temporal_workflow_stream_publish (the Signal that receives batched publishes), __temporal_workflow_stream_poll (the long-poll Update that subscribers use), and __temporal_workflow_stream_offset (the Query that reports the current head offset).
Workflow Stream hosting decision: work vs dedicated
Host the stream on the Workflow that does the work when the events come from what that Workflow is already orchestrating: an agent run, an order pipeline, a chat session. Use a dedicated Workflow for the stream when the stream should outlive any single producer, accept fan-in from multiple unrelated sources, or be subscribable before any work has started. Producers publish from outside the stream Workflow. The trade-off is explicit lifecycle management: a dedicated stream Workflow does not terminate on its own, so you need a Signal-driven shutdown or a Continue-As-New strategy.
Workflow Stream closing patterns: fixed sleep
Sleep between the last publish and the Workflow return so any in-flight poll has time to fetch the final event. First, the Workflow or its Activity publishes a sentinel event the subscriber recognizes (for example: {state: 'completed'}). Then the Workflow sleeps for a duration long enough to cover the subscriber's poll round-trip (30 seconds is a good default). Finally the Workflow returns. The cost is small: the Workflow stays open for the sleep duration but does no other work.
Workflow Stream closing patterns: acknowledgment handshake
The subscriber sends a Signal to the Workflow once it has received the sentinel event. The Workflow waits for that Signal up to a timeout, returning as soon as the ack arrives. First, the Workflow or its Activity publishes a sentinel event. Then the subscriber receives the sentinel and signals the Workflow. The Workflow's wait condition resolves and the Workflow returns. The timeout is still required because the subscriber may not be attached. With the ack, the typical case (subscriber online) exits as soon as the subscriber confirms receipt.
Workflow Stream exactly-once publishing guarantee
Each (publisher_id, sequence) batch lands in the log at most once, even if the publisher's underlying Signal is retried by the SDK or the network. Once an event is in the log, every subscriber that polls past its offset sees it. Deduplicate state is carried across Continue-As-New, so a retried publish that arrives after a rollover still lands at most once.
Workflow Stream ordering guarantee
The log imposes a single total order on all events, fixed once written: an event at offset N stays at offset N on every read. Within one publisher, events appear in publish order. Across concurrent publishers, the interleaving is what the Workflow saw when serializing inbound Signals. The order is stable once recorded, but not under application control. If event A must precede event B, publish them from the same publisher.
Workflow Stream Activity retries surface to subscribers
When an Activity that publishes events fails partway through and Temporal retries it, events for both attempts appear in the stream. An Activity that publishes three events and then errors, then retries and publishes its full output, delivers three partial events followed by the complete sequence. The Workflow itself sees only the successful attempt's return value, but a subscriber sees output from all attempts.
Workflow Stream Activity retry consumer pattern
The conventional pattern is for an Activity that detects it is on a retry attempt to publish a retry-sentinel event with force-flush. The consumer clears or annotates prior-attempt output when it sees the sentinel. Because the Workflow processes only Activity return values rather than reading the stream itself, its own state stays independent of these retried events.
Workflow Stream failure modes
Events still in a publisher's in-memory buffer are lost if the process crashes before they ship. Subscribers that handle an item and crash before persisting their next offset reprocess that item on resume.
Workflow Stream deduplication window settings
Publisher TTL (default: 15 minutes) is how long the Workflow retains per-publisher deduplicate state. Entries older than this are pruned at each Continue-As-New. Max retry duration (default: 10 minutes) is how long a Workflow Stream client retries a failed publish batch before dropping it and raising an error. These two settings must satisfy max retry duration < publisher TTL. If a publisher's retry window exceeds the dedup retention, the dedup state can age out before the retry lands, potentially producing duplicates.
Workflow Stream batch interval tuning
The batch interval (default: 2 seconds) is the maximum time between automatic flushes from the client. Lower it to make the stream feel live and raise it to amortize Signal cost. For an LLM token stream feeding a chat UI, 200 milliseconds is a good starting point: the user perceives it as live and a 30-second response generates roughly 150 publish Signals. Below 100 milliseconds, the per-Signal RPC overhead starts to dominate.
Workflow Stream force-flush tuning
For per-publish overrides where one event needs lower latency than the batch interval (the first delta of a response, or punctuated events like retry sentinels), set force-flush to true on that publish. Per-token force-flush on a 500-token completion produces 500 publish Signals, which is meaningful but tractable. Per-character force-flush is not.
Workflow Stream other tuning settings
Max batch size (default: unbounded) caps the number of items per batch. Without this, only batch interval bounds batch size. A hot publisher can accumulate enough items that the resulting Signal exceeds Temporal's per-message gRPC payload limit. For large items, offload via external storage so each item is a small reference. Poll cooldown (default: 100 ms) is the minimum interval between subscriber polls, skipped only when a poll response was capped at the 1 MB limit and more items remain.
Workflow Stream long-running workflow strategies
Subscribers automatically follow Continue-As-New chains. Workflow Ids are stable across Continue-As-New, so the subscriber fetches a fresh handle for the same Workflow Id and continues polling from its carried offset. To roll a long-running streaming Workflow over without subscribers seeing a gap: add an optional stream-state field to your Workflow input and pass it to the WorkflowStream constructor. When the Workflow decides to roll over, call the stream's Continue-As-New helper, which drains waiting subscribers, waits for in-flight handlers to finish, then calls continueAsNew with the snapshot.
Workflow Stream Continue-As-New payload optimization
Streams that carry large items can hit Temporal's per-payload size limit at the rollover. To keep the carried state small, offload large payloads via external storage so each item is a small reference, and use truncation to drop entries that subscribers have already consumed.
Workflow Stream Activity retry deduplication
Deduplication applies at the Signal layer, not the Activity layer. When Temporal retries an Activity, the retried execution constructs a new Workflow Stream client with its own client Id, so from the stream's perspective every attempt is a fresh publisher whose batches will not deduplicate against the prior attempt's. That is why retried-attempt events appear in the stream alongside the successful attempt's output.
What is a Workflow Stream
A Workflow Stream is a durable event channel hosted inside a Workflow. Publishers append events to topics on the stream. Subscribers attach to the Workflow by its Workflow Id, optionally filter by topic, and consume events by long-polling. Subscribers can disconnect and resume from where they left off without coordinating with anyone but the Workflow.
Workflow Streams use cases and limitations
Use Workflow Streams when outside observers need to follow the progress of a Workflow and its Activities as work happens, such as updating a UI as an AI agent works, surfacing status from a payment or order pipeline, or reporting intermediate results from a data job. Workflow Streams is not suited to ultra-low-latency cases like real-time voice. It targets modest fan-out: tens of publishers and subscribers per Workflow, not thousands.
What is Patching
A Patch defines a logical branch in a Workflow for a specific change, similar to a feature flag. It applies a code change to new Workflow Executions while avoiding disruptive changes to in-progress Workflow Executions. When you want to make substantive code changes that may affect existing Workflow executions, create a patch.
Patching best practice - newest code at top
When patching in new code, always put the newest code at the top of an if-patched-block. This ensures that when running a fresh execution and not replaying, the patched statement will return true and run the new code. Arranging conditionals differently, such as checking older versions first, will cause new executions to use older code and miss the newest version.
Workflow Versioning strategies
Temporal offers two Versioning strategies: (1) Worker Versioning - keep Workers tied to specific code revisions so that old Workers can run old code paths and new Workers can run new code paths (recommended approach); (2) Versioning with patching - make sure code changes are compatible across versions of the Workflow. Either strategy or a combination can be used.
Schedule Pause functionality
A Schedule can be Paused. When a Schedule is Paused, the Spec has no effect. However, you can still force manual actions by using the temporal schedule trigger command. A notes field can be updated on pause or resume to store an explanation for the current state. Pausing a Schedule is different from pausing a Workflow Execution. Schedule Pause stops the Schedule from taking future Actions, but it doesn't pause or otherwise affect any Workflow Executions that the Schedule already started.
Schedule definition and purpose
A Schedule contains instructions for starting a Workflow Execution at specific times. Schedules provide a more flexible and user-friendly approach than Temporal Cron Jobs. A Schedule has an identity and is independent of a Workflow Execution, unlike a Temporal Cron Job, which relies on a cron schedule as a property of the Workflow Execution.
Schedule vs one-time workflow start
For triggering a Workflow Execution at a specific one-time future point rather than on a recurring schedule, the Start Delay option should be used instead of a Schedule.
Schedule Action properties
The Action of a Schedule is where the Workflow Execution properties are established, such as Workflow Type, Task Queue, parameters, and timeouts. Workflow Executions started by a Schedule have the following additional properties: the Action's timestamp is appended to the Workflow Id; the TemporalScheduledStartTime Search Attribute is added with the value being the Action's timestamp; and the TemporalScheduledById Search Attribute is added with the value being the Schedule Id.
Schedule Spec definition
The Schedule Spec defines when the Action should be taken. Unless many Schedules have Actions scheduled at the same time, Actions should generally start within 1 second of the specified time. There are two kinds of Schedule Spec: a simple interval, like every 30 minutes (aligned to start at the Unix epoch, and optionally including a phase offset), and a calendar-based expression, similar to cron expressions.