Start-update-with-start waits for update acceptance before completion
start-update-with-start sends a message to a Workflow Execution to invoke an Update handler, and waits for the update to be accepted or rejected. If the Workflow Execution is not running, then a new workflow execution is started and the update is sent. Use temporal workflow start-update-with-start --update-name YourUpdate --update-input '{"update-key": "update-value"}' --update-wait-for-stage accepted --workflow-id YourWorkflowId --type YourWorkflowType --task-queue YourTaskQueue --id-conflict-policy Fail --input '{"wf-key": "wf-value"}'
Temporal CLI query command syntax with SQL-like filters
The temporal workflow query command sends a Query to a Workflow Execution by Workflow ID to retrieve its state. This synchronous operation exposes the internal state of a running Workflow Execution. Queries can be sent to both running and completed Workflow Executions using temporal workflow query --workflow-id YourWorkflowId --type YourQueryType --input '{"YourInputKey": "YourInputValue"}'
Signal sends asynchronous notification to Workflow Execution
A Signal is an asynchronous notification sent to a running Workflow Execution by its Workflow ID. The Signal is written to the History. When you include --input, that data is available for the Workflow Execution to consume. Use temporal workflow signal --workflow-id YourWorkflowId --name YourSignal --input '{"YourInputKey": "YourInputValue"}'
Signal-with-start sends signal or starts workflow if not running
signal-with-start sends an asynchronous notification (Signal) to a Workflow Execution. If the Workflow Execution is not running or is not found, it starts the workflow then sends the signal. Use temporal workflow signal-with-start --signal-name YourSignal --signal-input '{"some-key": "some-value"}' --workflow-id YourWorkflowId --type YourWorkflowType --task-queue YourTaskQueue --input '{"some-key": "some-value"}'
Update is synchronous call that can change workflow state
An Update is a synchronous call to a Workflow Execution that can change its state, control its flow, and return a result.
Temporal CLI update execute sends message and waits for completion
temporal workflow update execute sends a message to a Workflow Execution to invoke an Update handler, and waits for the update to complete or fail. You can also use this to wait for an existing update to complete by submitting an existing update ID. Use temporal workflow update execute --workflow-id YourWorkflowId --name YourUpdate --input '{"some-key": "some-value"}'
Temporal CLI update start waits for acceptance only
temporal workflow update start sends a message to a Workflow Execution to invoke an Update handler, and waits for the update to be accepted or rejected. You can subsequently wait for the update to complete by using temporal workflow update execute. Use temporal workflow update start --workflow-id YourWorkflowId --name YourUpdate --input '{"some-key": "some-value"}' --wait-for-stage accepted
Execute-update-with-start sends update to workflow or starts workflow and sends update
execute-update-with-start sends a message to a Workflow Execution to invoke an Update handler, and waits for the update to complete. If the Workflow Execution is not running, then a new workflow execution is started and the update is sent. Use temporal workflow execute-update-with-start --update-name YourUpdate --update-input '{"update-key": "update-value"}' --workflow-id YourWorkflowId --type YourWorkflowType --task-queue YourTaskQueue --id-conflict-policy Fail --input '{"wf-key": "wf-value"}'
Query reject-condition flag for state validation
The --reject-condition flag is an optional flag for rejecting Queries based on Workflow state. Accepted values are: not_open, not_completed_cleanly. This flag is available for query, metadata, and stack commands.
Update describe returns update status and result
temporal workflow update describe returns information about an Update's current status given a Workflow Execution and an Update ID, including a result if it has finished. Use temporal workflow update describe --workflow-id YourWorkflowId --update-id YourUpdateId
Update result waits for completion and prints result
temporal workflow update result waits for the Update to complete or fail and prints the result. Use temporal workflow update result --workflow-id YourWorkflowId --update-id YourUpdateId
Update ID defaults to UUID if unset
The --update-id flag specifies an Update ID. If unset, it defaults to a UUID. The Update ID must be unique per Workflow Execution.
.NET Temporal Client for Workflow messages
A Temporal Client in .NET enables communication with the Temporal Service to perform actions such as starting Workflow Executions, sending Signals and Queries to Workflow Executions, and getting Workflow results.
AddReceive for receiving Channel messages in Selector
The selector.AddReceive(channel, callback) method is the primary mechanism to receive messages from Channels. The callback receives the ReceiveChannel and a more boolean indicating whether there are more messages.
Channel receive must be explicitly consumed in AddReceive callback
Merely matching on a channel does not consume the message. It must be explicitly consumed with a c.Receive(ctx, &value) call inside the AddReceive callback.
Use selector.HasPending to prevent signal loss on Workflow close
The selector.HasPending API can be used to ensure that signals are not lost when a Workflow is closed, for example by ContinueAsNew.
Selector Channel receive example
Example showing how to receive information from a Channel in a Selector:
```go
// receive information from a Channel
var signalVal string
channel := workflow.GetSignalChannel(ctx, channelName)
selector.AddReceive(channel, func(c workflow.ReceiveChannel, more bool) {
c.Receive(ctx, &signalVal)
// do something with received information
})
```
Query handler is read-only and synchronous
A Query handler is a synchronous operation that retrieves state from a Workflow Execution. It can inspect Workflow state but must not mutate it. Query handlers cannot perform async operations such as executing an Activity. Use SetQueryHandler to set a Query handler that listens for a Query by name.
SetQueryHandler function signature in Go
Use workflow.SetQueryHandler(ctx, queryName, func(input InputType) (OutputType, error)) to register a Query handler. The handler must be a function that returns two values: a serializable result and an error.
Signal Channel receives asynchronous messages
A Signal is an asynchronous message sent to a running Workflow Execution to change its state and control its flow. Handle Signal messages by receiving them from their channel using workflow.GetSignalChannel(ctx, signalName).Receive(ctx, &signalInput).
Drain Signal channel before workflow completion
Before completing the Workflow or using Continue-As-New, ensure you perform an asynchronous drain on the Signal channel using ReceiveAsync() in a loop. Otherwise, the Signals will be lost.
Delay GetSignalChannel until workflow initialization completes
Delay calling workflow.GetSignalChannel until the Workflow initialization needed to process the Signal channel has finished. This is safe because the SDK buffers signals when there are no channels created for them.
Update handler is synchronous and can mutate state
An Update is a trackable synchronous request sent to a running Workflow Execution. It can change Workflow state, control its flow, and return a result. The sender must wait until the Worker accepts or rejects the Update, and may wait further to receive a returned value or an exception.
SetUpdateHandler and SetUpdateHandlerWithOptions registration
Register an Update handler for a given name using workflow.SetUpdateHandler or workflow.SetUpdateHandlerWithOptions. The handler must be a function that accepts a workflow.Context as its first parameter and can return either a serializable value with an error or just an error.
Update validator function requirements
To set a validator for an Update, pass the validator function in workflow.UpdateHandlerOptions when calling workflow.SetUpdateHandlerWithOptions. The validator must be a function that accepts the same argument types as the handler and returns a single value of type error. Validators are optional and used to reject an Update before it is written to History.
Update rejection with validator error
To reject an Update, return an error or panic in the validator function. The Workflow's WorkflowPanicPolicy determines how panics are handled inside the validator function.
WorkflowExecutionUpdateAccepted event is written when validator passes
The WorkflowExecutionUpdateAccepted event is written into History when the Update passes validation (or is automatically accepted if there is no validator). When a validator throws an error, the Update is rejected and WorkflowExecutionUpdateAccepted will not be added to Event History; the caller receives an 'Update failed' error.
GetCurrentUpdateInfo to access update metadata
Use workflow.GetCurrentUpdateInfo() to obtain information about the current Update, including the Update ID. This is useful for deduplication when using Continue-As-New.
Update handlers support Activities, Child Workflows, and Timers
Update handlers can use Activities, Child Workflows, durable workflow.Sleep Timers, workflow.Await conditions, and more. See Blocking handlers and Workflow message passing for safe usage guidelines.
Delay SetUpdateHandler until workflow initialization is ready
Delay calling workflow.SetUpdateHandler until the Workflow initialization needed by Update handlers is finished. The SDK buffers messages when there are no registered handlers for them. Note that workflow.SetUpdateHandler will immediately invoke the handler of buffered Updates with matching types, which could lead to out-of-order processing of messages with different types.
Continue-as-New not supported within Update handlers
Temporal does not support Continue-as-New functionality within Update handlers. Complete all handlers before using Continue-as-New. Use Continue-as-New from your main Workflow function, just as you would complete or fail a Workflow Execution.
QueryWorkflow API for sending queries from client
Use Client.QueryWorkflow or Client.QueryWorkflowWithOptions to send a Query from a Temporal Client. Sending a Query does not add events to a Workflow's Event History.
Query can be sent to closed workflows
You can send Queries to closed Workflow Executions within a Namespace's Workflow retention period, including Workflows that have completed, failed, or timed out. Querying terminated Workflows is not supported.
Worker must be online to process queries
A Worker must be online and polling the Task Queue to process a Query.
SignalWorkflow API from client
Use Client.SignalWorkflow to send a Signal to a Workflow Execution from a Temporal Client. Pass in both the Workflow ID and Run ID to uniquely identify the Workflow Execution. If only the Workflow ID is supplied (provide an empty string as the Run ID), the running Workflow Execution receives the Signal.
SignalWorkflow returns when server accepts signal
The Client.SignalWorkflow call returns when the server accepts the Signal; it does not wait for the Signal to be delivered to the Workflow Execution.
WorkflowExecutionSignaled event in History
The WorkflowExecutionSignaled Event appears in the Workflow's Event History when a Signal is sent from a client.
Send External Signal from workflow to workflow
A Workflow can send a Signal to another Workflow using workflow.SignalExternalWorkflow(ctx, targetWorkflowID, targetRunID, signalName, signal).Get(ctx, nil). A SignalExternalWorkflowExecutionInitiated Event appears in the sender's Event History, and a WorkflowExecutionSignaled Event appears in the recipient's Event History.
Signal-With-Start creates or signals existing workflow
Signal-With-Start is used from the Client. Use Client.SignalWithStartWorkflow to start a Workflow Execution (if not already running) and pass it the Signal at the same time. If there is a Workflow running with the given Workflow ID, it will be signaled. If there is not, a new Workflow will be started and immediately signaled. This API does not take a Run ID as a parameter because the Workflow Execution might not exist.
UpdateWorkflow API for sending updates from client
Use Client.UpdateWorkflow to send an Update to a Workflow Execution. You must provide the Workflow ID; specifying a Run ID is optional. If you supply only the Workflow ID (and provide an empty string as the Run ID), the running Workflow Execution receives the Update. You must provide a WaitForStage parameter that controls the stage the update must reach before returning a handle to the caller.
WaitForStage controls update return timing
The WaitForStage parameter in UpdateWorkflow controls when the handle is returned: If WorkflowUpdateStageCompleted, the handle is returned after the Update completes. If WorkflowUpdateStageAccepted, the handle is returned after the Update is accepted (after the validator has run, if there is one).
Updates cannot be sent directly between workflows
You can't send Updates directly from one Workflow to another. If you need to send Updates across Workflows, like to Child Workflows, use an Activity.
WorkflowExecutionUpdateAccepted and Completed events in History
WorkflowExecutionUpdateAccepted is added to the Event History when the Worker confirms that the Update passed validation. WorkflowExecutionUpdateCompleted is added to the Event History when the Worker confirms that the Update has finished.
UpdateWithStartWorkflow API
Use Client.UpdateWithStartWorkflow to send an Update that checks whether an already-running Workflow with that ID exists. If the Workflow exists, the Update is processed. If the Workflow does not exist, a new Workflow Execution is started with the given ID, and the Update is processed before the main Workflow method starts to execute. It returns once the requested Update wait stage has been reached or when a provided context times out.
UpdateWithStartWorkflow requires StartWorkflowOptions
UpdateWithStartWorkflow requires StartWorkflowOptions with the Workflow ID Conflict Policy set to 'Use Existing' to ensure your code can be executed again in case of a Client failure. Not all StartWorkflowOptions are allowed; for example, specifying a Cron Schedule will result in an error.
UpdateWithStartWorkflow uses NewWithStartWorkflowOperation
Use Client.NewWithStartWorkflowOperation to specify the workflow options, method and arguments for UpdateWithStartWorkflow. A WithStartWorkflowOperation can only be used once; re-using a previously used operation returns an error.
Blocking handlers allow async operations
Signal and Update handlers can block. This allows you to use Activities, Child Workflows, durable workflow.Sleep Timers, workflow.Await conditions, etc. Handler executions and the main Workflow method run concurrently, with switching occurring between them at await calls.
workflow.Await prevents handler from proceeding until condition is true
Use workflow.Await(ctx, func() bool) to prevent handler code from proceeding until a condition returns true. This is important for: waiting until a specific Update has arrived, waiting in a handler until it is appropriate to continue, and waiting in the main Workflow until all active handlers have finished.
AllHandlersFinished to ensure handlers complete before workflow ends
Use workflow.Await(ctx, func() bool { return workflow.AllHandlersFinished(ctx) }) to ensure all message handlers complete before the Workflow finishes. This prevents the Workflow from completing or continuing-as-new while a handler is still waiting on an async task, which would interrupt the handler and cause client errors when trying to retrieve Update results.
UnfinishedPolicy to silence handler completion warnings
By default, the Worker logs a warning if a Workflow Execution finishes with unfinished Update handler executions. Silence these warnings on a per-handler basis by setting the UnfinishedPolicy field to workflow.HandlerUnfinishedPolicyAbandon on the workflow.UpdateHandlerOptions struct.
workflow.Mutex prevents concurrent handler execution
Use workflow.Mutex to prevent concurrent handler execution and ensure only one handler instance can execute a specific section of code at any given time. Call mutex.Lock(ctx) to acquire the lock and defer mutex.Unlock() to release it. This prevents race conditions when multiple handler instances run simultaneously.
Update failure causes in Go SDK
Update failures can be caused by: a failed Child Workflow, a failed Activity if activity retries are set to a finite number, the Workflow author returning an error, or a panic in the handler depending on WorkflowPanicPolicy.
Workflow Task Failure affects Update request handling
A Workflow Task Failure causes the server to retry Workflow Tasks indefinitely. If the Update request has not been accepted by the server, you receive a FAILED_PRECONDITION error. If the Update request has been accepted, it is durable and you can use WorkflowUpdateHandle to fetch the Update result once the Workflow is healthy again after a code deploy.
Update handler blocked by workflow completion error
If the Workflow finishes while an Update handler execution is in progress, you will receive a ServiceError 'workflow execution already completed'. This can happen if the Workflow was canceled, failed, completed normally, or continued-as-new and the Workflow author did not wait for handlers to be finished.
Query failure causes in Go SDK
Query failures are caused when there is no Workflow Worker polling the Task Queue (ServiceError with status FAILED_PRECONDITION) or when any panic occurs in a Query handler (QueryFailed error). This differs from Signal and Update, where panics can lead to Workflow Task Failure instead.
Query handler blocking causes Workflow Task to fail
If the Query handler blocks the thread for too long without yielding, it can cause the Workflow Task to fail.
Message values must be serializable
Values sent in messages, and the return values of message handlers and the main Workflow function, must be serializable.
Use struct for message input over multiple parameters
Prefer using a single struct over multiple input parameters for message handlers. This allows you to add fields without changing the calling signature.
Example of Query handler in Go
Example showing Query handler using SetQueryHandler with a handler function that inspects Workflow state and returns a list of supported languages based on an input flag:
type Language string
const GetLanguagesQuery = "GetLanguages"
type GetLanguagesInput struct {
IncludeUnsupported bool
}
func GreetingWorkflow(ctx workflow.Context) (string, error) {
greeting := map[Language]string{English: "Hello", Chinese: "你好,世界"}
err := workflow.SetQueryHandler(ctx, GetLanguagesQuery, func(input GetLanguagesInput) ([]Language, error) {
if input.IncludeUnsupported {
return []Language{Chinese, English, French, Spanish, Portuguese}, nil
} else {
return maps.Keys(greeting), nil
}
})
...
}
Example of Signal handler in Go
Example showing Signal handler using GetSignalChannel and Receive to block until approval signal arrives:
const ApproveSignal = "approve"
type ApproveInput struct {
Name string
}
func GreetingWorkflow(ctx workflow.Context) error {
logger := workflow.GetLogger(ctx)
approverName := ""
var approveInput ApproveInput
workflow.GetSignalChannel(ctx, ApproveSignal).Receive(ctx, &approveInput)
approverName = approveInput.Name
logger.Info("Received approval", "Approver", approverName)
...
}