ID conflict policy options for workflow startup
The --id-conflict-policy flag determines how to resolve a conflict when spawning a new Workflow Execution with a particular Workflow Id used by an existing Open Workflow Execution. Accepted values are: Fail, UseExisting, TerminateExisting.
First-execution-run-id targets last workflow in chain
The --first-execution-run-id flag is a Parent Run ID parameter. When used, the update is sent to the last Workflow Execution in the chain started with this Run ID. This is used in temporal workflow update execute and temporal workflow start-update-with-start commands.
Workflow execute command blocks until completion
temporal workflow execute establishes a new Workflow Execution and directs its progress to stdout. The command blocks and returns when the Workflow Execution completes. Use temporal workflow execute --workflow-id YourWorkflowId --type YourWorkflow --task-queue YourTaskQueue --input '{"some-key": "some-value"}' for workflows requiring input with valid JSON.
Workflow metadata displays user-set summary and details
The metadata command issues a Query for and displays user-set metadata like summary and details for a specific Workflow Execution. Use temporal workflow metadata --workflow-id YourWorkflowId
Pause and unpause experimental workflow features
Pause and unpause are experimental features that may change in the future. pause pauses a Workflow Execution and unpause unpauses a previously paused Workflow Execution. Both accept --reason flag (defaults to message with current user's name).
Terminate vs Cancel - termination prevents workflow cleanup
Terminating a Workflow Execution is different from canceling. Workflow code cannot see or respond to terminations. To perform clean-up work in your Workflow code, use temporal workflow cancel instead of terminate.
ID reuse policy options for workflow execution
The --id-reuse-policy flag specifies the re-use policy for the Workflow ID in new Workflow Executions. Accepted values are: AllowDuplicate, AllowDuplicateFailedOnly, RejectDuplicate, TerminateIfRunning.
Workflow count shows execution count regardless of state
The count command shows a count of Workflow Executions, regardless of execution state (running, terminated, etc). Use --query to select a subset of Workflow Executions. Use temporal workflow count --query YourQuery
Workflow result blocks until completion
The result command waits for and prints the result of a Workflow Execution. Use temporal workflow result --workflow-id YourWorkflowId
Workflow headers are different from gRPC headers
Temporal workflow headers (set via --headers flag) are different from gRPC headers. They are in 'KEY=VALUE' format where keys must be identifiers and values must be JSON values. May be passed multiple times to set multiple Temporal headers. Note: These are workflow headers, not gRPC headers.
Batch cancellation and deletion with visibility queries
Bulk workflow operations (cancel, delete, signal, terminate, update-options) can be performed via a visibility Query list filter using --query flag. This applies the operation to all Workflow Executions matching the query results. The --rps flag limits batch requests per second, and --reason provides the reason for batch operation (defaults to user name). Use --yes flag to skip confirmation prompts.
Workflow delete removes execution asynchronously
The delete command deletes a Workflow Execution and its Event History with asynchronous execution. If the Execution is Running, the Service terminates it before deletion. WARNING: Deleting Workflow Executions in a global Namespace removes them from all replicas. Requests sent to a passive cluster are forwarded to the active cluster by default; to target the passive cluster directly, specify --grpc-meta xdc-redirection=false.
Workflow cancel records WorkflowExecutionCancelRequested event
Canceling a running Workflow Execution records a WorkflowExecutionCancelRequested event in the Event History. The Service schedules a new Command Task, and the Workflow Execution performs any cleanup work supported by its implementation.
Start-delay for workflow delayed execution
The --start-delay flag specifies a delay before starting the Workflow Execution. Can't be used with cron schedules. If the Workflow receives a signal or update prior to this time, the Workflow Execution starts immediately.
Workflow list with query filter and pagination
The list command lists Workflow Executions. The optional --query limits the output to Workflows matching a Query. Use --archived flag to view archived Workflow Executions (experimental). Use --limit for maximum number of executions to display and --page-size for maximum number to fetch at a time from server.
.NET check Workflow status with DescribeAsync
In .NET, to get the current status of a Workflow Execution, use DescribeAsync() method on a Workflow handle obtained from GetWorkflowHandle(). If the Workflow does not exist, this call fails.
.NET get Workflow result with GetResultAsync
In .NET, to get the result of a Workflow Execution, use GetWorkflowHandle(workflowId) to get a Workflow handle, then call GetResultAsync<T>() on the handle to await the result. This can be done synchronously (blocking) or asynchronously. The Workflow Id, Run Id, and Namespace uniquely identify a Workflow Execution.
.NET start Workflow with ExecuteWorkflowAsync or StartWorkflowAsync
In .NET, use ExecuteWorkflowAsync() to start a Workflow Execution and wait for the result, or StartWorkflowAsync() to start without waiting. Both methods require a WorkflowOptions object with a Workflow Id (id parameter) and Task Queue (taskQueue parameter). ExecuteWorkflowAsync returns the Workflow result directly.
.NET Temporal Client usage restrictions
A Temporal Client cannot be initialized and used inside a Workflow in .NET. However, it is acceptable and common to use a Temporal Client inside an Activity to communicate with a Temporal Service.
.NET TLS certificate rotation for Temporal Client
In .NET, TlsOptions is immutable on an existing connection. To rotate an mTLS client certificate, create a new TemporalClient with the new certificate and key bytes, then assign it to the Worker's Client property: worker.Client = newClient. This replaces the connection for subsequent calls without interrupting calls already in flight.
.NET Temporal Cloud connection with API key
To connect to Temporal Cloud in .NET using an API key, set the Namespace as <namespace_id>.<account_id>, the endpoint as <namespace>.<account>.tmprl.cloud:7233, and provide the ApiKey in TemporalClientConnectOptions. The API key can be set via code, environment variables (TEMPORAL_API_KEY), or configuration file.
.NET Temporal Client API key update on existing connection
In .NET, to update an API key on an existing Temporal Client connection, update the ApiKey property directly: myClient.Connection.ApiKey = newKeyValue. This allows key rotation without recreating the client.
.NET Temporal Cloud connection with mTLS
To connect to Temporal Cloud in .NET using mTLS, set the Namespace as <namespace_id>.<account_id>, the endpoint as <namespace>.<account>.tmprl.cloud:7233, and provide TlsOptions with ClientCert and ClientPrivateKey byte arrays. Configure via code: new TemporalClientConnectOptions with Tls property containing new TlsOptions with ClientCert and ClientPrivateKey from file bytes.
.NET Temporal Client creation with ConnectAsync
Use TemporalClient.ConnectAsync to create a Temporal Client in .NET. Connection options include the Temporal Server address, Namespace, and optionally TLS configuration. When connecting to a local Temporal Service (such as the Temporal CLI dev server), if no host/port is specified, the default connection is 127.0.0.1:7233 and the 'default' Namespace.
.NET Temporal Client direct code configuration
In .NET, you can specify connection options directly in code by passing a TemporalClientConnectOptions object to TemporalClient.ConnectAsync. Set TargetHost and Namespace properties directly in the options object. This approach is convenient for local development and testing, and can be combined with loading base configuration from environment variables or files.
.NET configuration file for Temporal Client using TOML
The .NET SDK supports loading Temporal Client configuration from a TOML file using the ClientEnvConfig.LoadClientConnectOptions method. The configuration file can be located using the TEMPORAL_CONFIG_FILE environment variable or defaults to ~/.config/temporalio/temporal.toml. The file can define multiple profiles, each with connection options. Environment variables have higher precedence than configuration file settings.
.NET get Workflow result code example
Example of getting a Workflow result in .NET:
```csharp
var handle = client.GetWorkflowHandle("my-workflow-id");
var result = await handle.GetResultAsync<string>();
Console.WriteLine("Result: {0}", result);
```
This retrieves an existing Workflow by its ID and gets the result as a string.
.NET environment variables for Temporal Client connection
The .NET SDK supports loading Temporal Client configuration from environment variables using ClientEnvConfig.LoadClientConnectOptions(). Key environment variables: TEMPORAL_NAMESPACE sets the namespace, TEMPORAL_ADDRESS sets the server address. Default values are 'default' for namespace and 'localhost:7233' for address when omitted.
.NET start Workflow code example
Example of starting a Workflow in .NET:
```csharp
var result = await client.ExecuteWorkflowAsync(
(MyWorkflow wf) => wf.RunAsync(),
new(id: "my-workflow-id", taskQueue: "my-task-queue"));
Console.WriteLine("Result: {0}", result);
```
This starts a Workflow with ID "my-workflow-id" on task queue "my-task-queue" and waits for completion.
.NET environment variables precedence over configuration file
In .NET Temporal Client configuration, environment variables have higher precedence than configuration file settings. If the same connection option is set in both the configuration file and as an environment variable, the environment variable value overrides the configuration file value.
.NET CancellationTokenSource.Cancel instead of CancelAsync in workflows
Use CancellationTokenSource.Cancel instead of CancellationTokenSource.CancelAsync in workflows.
.NET workflow logging example
Example showing .NET workflow logging:
```csharp
[Workflow]
public class MyWorkflow
{
[WorkflowRun]
public async Task<string> RunAsync(string name)
{
Workflow.Logger.LogInformation("Starting workflow for {Name}", name);
// ...
}
}
```
.NET workflow example with activity execution
Example showing .NET workflow with activity execution:
```csharp
using Temporalio.Workflows;
[Workflow]
public class MyWorkflow
{
[WorkflowRun]
public async Task<string> RunAsync(string name)
{
var param = MyActivityParams("Hello", name);
return await Workflow.ExecuteActivityAsync(
(MyActivities a) => a.MyActivity(param),
new() { StartToCloseTimeout = TimeSpan.FromMinutes(5) });
}
}
```
.NET custom workflow type name
Set a custom workflow type name using the [Workflow] attribute parameter, for example [Workflow("MyDifferentWorkflowName")]. If the name parameter is not specified, the workflow name defaults to the unqualified class name.
.NET workflow analyzer rules to disable in .editorconfig
For .workflow.cs files, disable these analyzer rules: CA1024 (properties for queries), CA1822 (static methods), CA2007 (ConfigureAwait), CA2008 (task scheduler), CA5394 (non-crypto random), CS1998 (async without await), and VSTHRD105 (implicit current scheduler).
.NET workflow file naming convention for analyzers
Use the .workflow.cs file extension for files containing workflows to ensure analyzer rule suppressions apply only to workflow code.
.NET SDK adds event source listener for task scheduler validation
By default, the Temporal .NET SDK adds an event source listener for info-level task events to catch wrong scheduler use. When code runs in a workflow and accidentally starts a task in another scheduler, an InvalidWorkflowOperationException is thrown which pauses the workflow. This can be disabled by setting DisableWorkflowTracingEventListener to true in worker options.
.NET workflow synchronization primitives
Use Temporalio.Workflows.Semaphore or Temporalio.Workflows.Mutex instead of System.Threading.Semaphore, System.Threading.SemaphoreSlim, or System.Threading.Mutex in workflows to avoid deadlocking.
.NET Workflow.WhenAnyAsync instead of Task.WhenAny
Use Workflow.WhenAnyAsync instead of Task.WhenAny for workflows. This applies primarily to enumerable sets of tasks with results or more than 2 tasks with results.
.NET ConfigureAwait requirements in workflows
If ConfigureAwait is used in workflows, it must be ConfigureAwait(true). ConfigureAwait(false) will not use the current context and breaks determinism. There is no significant performance benefit to ConfigureAwait in workflows.
.NET Task.Run causes non-determinism in workflows
Do not use Task.Run in workflows as it uses the default scheduler and puts work on the thread pool. Use Workflow.RunTaskAsync instead, or use Task.Factory.StartNew with current scheduler or instantiate Task and run Task.Start on it.
.NET Workflow.Unsafe.IsReplayingHistoryEvents for query and update validators
Use Workflow.Unsafe.IsReplayingHistoryEvents to detect when code runs during read-only operations like queries and update validators. This is false during those operations, unlike IsReplaying which is true during replay.
.NET Workflow.Unsafe.IsReplaying for non-deterministic operations
Use Workflow.Unsafe.IsReplaying to guard code that should only run on the first execution, such as emitting metrics or sending external notifications. Never use this to affect workflow business logic as branching on replay status breaks determinism.
.NET workflow example with WorkflowInit constructor
Example showing .NET workflow with [WorkflowInit] constructor:
```csharp
[Workflow]
public class WorkflowInitWorkflow
{
public record Input(string Name);
private readonly string nameWithTitle;
private bool titleHasBeenChecked;
[WorkflowInit]
public WorkflowInitWorkflow(Input input) =>
nameWithTitle = $"Knight {input.Name}";
[WorkflowRun]
public async Task<string> RunAsync(Input ignored)
{
await Workflow.WaitConditionAsync(() => titleHasBeenChecked);
return $"Hello, {nameWithTitle}";
}
}
```
.NET workflow RunAsync method signature
The [WorkflowRun] method must be async and is the entry point for workflow execution. It receives workflow parameters and can return any serializable type. All workflow parameters must be serializable.
.NET Workflow.WhenAllAsync instead of Task.WhenAll
Use Workflow.WhenAllAsync instead of Task.WhenAll in workflows to ensure determinism.
.NET workflow class definition with attributes
In the .NET SDK, workflows are defined as classes with the [Workflow] attribute from the Temporalio.Workflows namespace. The entry point method must be marked with the [WorkflowRun] attribute and must be an asynchronous method on the same class.
Use Workflow.Random for deterministic random numbers in .NET
Workflows must use Workflow.Random to get a deterministic random instance seeded per workflow execution, instead of using standard random classes. Use Workflow.NewGuid() instead of Guid.NewGuid().
Use Workflow.UtcNow for current time in .NET workflows
Workflows must use Workflow.UtcNow instead of DateTime.Now or DateTime.UtcNow. It returns the time of the last workflow task, which is consistent across replays.
Use Workflow.Logger instead of Console.WriteLine in .NET
Workflows must use Workflow.Logger instead of Console.WriteLine or a manually resolved logger. The SDK logger appends workflow details to every log entry and skips logging during replay.
.NET workflow constructor initialization with WorkflowInit
The [WorkflowInit] attribute can be applied to a workflow constructor to give it access to workflow input parameters. When used, the constructor must have the same parameters with the same types as the [WorkflowRun] method. The SDK ensures the constructor receives workflow input arguments before RunAsync is called.
Cancellation vs Termination in .NET
Cancellation provides a graceful way to stop Workflow Execution by allowing the Workflow code to handle the cancellation request. Termination forcefully and immediately stops Workflow Execution, resembling killing a process. Termination records a WorkflowExecutionTerminated event in Event History and the Workflow code gets no chance to handle it. In most cases, canceling is preferable because it allows the Workflow to finish gracefully; terminate only if the Workflow is stuck and cannot be canceled normally.
.NET cancellation example with cleanup activity
Example showing how to handle cancellation in a .NET Workflow with cleanup:
```csharp
[WorkflowRun]
public async Task RunAsync()
{
try
{
await Workflow.ExecuteActivityAsync(
(MyActivities a) => a.MyNormalActivity(),
new() { ScheduleToCloseTimeout = TimeSpan.FromMinutes(5) });
}
catch (Exception e) when (TemporalException.IsCanceledException(e))
{
Workflow.Logger.LogError(e, "Cancellation occurred, performing cleanup");
await Workflow.ExecuteActivityAsync(
(MyActivities a) => a.MyCancellationCleanupActivity(),
new()
{
ScheduleToCloseTimeout = TimeSpan.FromMinutes(5),
CancellationToken = CancellationToken.None,
});
throw;
}
}
```
Terminate workflow in .NET
Use the TerminateAsync() method on the WorkflowHandle to terminate a Workflow Execution. Get a workflow handle using myClient.GetWorkflowHandle("workflow-id"), then call await handle.TerminateAsync(). Workflow Executions can also be terminated directly from the WebUI with a custom note logged.
Request cancellation from client in .NET
Use CancelAsync() on the WorkflowHandle to cancel a Workflow Execution. Call handle.CancelAsync() which returns when cancellation is received by the server. To get a workflow handle, use myClient.GetWorkflowHandle("workflow-id"), optionally passing a run ID to make it specific to a run, or use a handle returned from StartWorkflowAsync. Wait on the handle's result to wait for cancellation to be applied.
Handle cancellation in .NET Workflow
Cancellation Requests on Workflows cancel the Workflow.CancellationToken, which is implicitly used for all calls within the workflow including Timers and Activities, so cancellation propagates to them. Catch TemporalException using TemporalException.IsCanceledException(e) to detect cancellation. When handling cancellation, use CancellationToken.None when calling cleanup activities if you don't want them to be cancellable, since the default Workflow.CancellationToken is already marked as cancelled. The default behavior for activity cancellation is to send the cancellation but not wait for it to be handled, controlled by the CancellationType option.
Workflow Type as function reference or string in Go SDK
If the invocation process has direct access to the function, pass the Workflow Type name as a function variable: ExecuteWorkflow(..., YourWorkflowDefinition, ...). If no direct access, provide as a string: ExecuteWorkflow(..., "YourWorkflowDefinition", ...)
ExecuteWorkflow example in Go SDK
workflowOptions := client.StartWorkflowOptions{
TaskQueue: "your-task-queue",
}
workflowRun, err := temporalClient.ExecuteWorkflow(context.Background(), workflowOptions, YourWorkflowDefinition, param)
if err != nil {
// handle error
}
Start Workflow Execution in Go SDK
Use the ExecuteWorkflow() method on the Client. It requires: instance of context.Context, instance of StartWorkflowOptions, Workflow Type name, and all variables to pass to the Workflow Execution. ExecuteWorkflow() returns a Future (WorkflowRun) which can be used to get the result.
WorkflowExecutionErrorWhenAlreadyStarted in Go SDK
Set WorkflowExecutionErrorWhenAlreadyStarted in StartWorkflowOptions. Type: bool. Default: false.