Skip to main content

Interrupt a Workflow - .NET SDK feature guide

This page shows how to interrupt a Workflow Execution.

You can interrupt a Workflow Execution in one of the following ways:

  • Cancel: Canceling a Workflow provides a graceful way to stop Workflow Execution.
  • Terminate: Terminating a Workflow forcefully stops Workflow Execution. Terminating a Workflow forcefully stops Workflow Execution. This action resembles killing a process.
    • The system records a WorkflowExecutionTerminated event in the Workflow History.
    • The termination forcefully and immediately stops the Workflow Execution.
    • The Workflow code gets no chance to handle termination.
    • A Workflow Task doesn't get scheduled.

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.

Cancellation

To give a Workflow and its Activities the ability to be cancelled, do the following:

  • Handle a Cancellation request within a Workflow.
  • Set Activity Heartbeat Timeouts.
  • Listen for and handle a Cancellation request within an Activity.
  • Send a Cancellation request from a Temporal Client.

Handle Cancellation in Workflow

How to handle a Cancellation in a Workflow in .NET.

Workflow Definitions can be written to respond to cancellation requests. It is common for an Activity to be run on Cancellation to perform cleanup.

Cancellation Requests on Workflows cancel the Workflow.CancellationToken. This is the token that is implicitly used for all calls within the workflow as well (e.g. Timers, Activities, etc) and therefore cancellation is propagated to them to be handled and bubble out.

[WorkflowRun]
public async Task RunAsync()
{
try
{
// Whether this workflow waits on the activity to handle the cancellation or not is
// dependent upon the CancellationType option. We leave the default here which sends the
// cancellation but does not wait on it to be handled.
await Workflow.ExecuteActivityAsync(
(MyActivities a) => a.MyNormalActivity(),
new() { ScheduleToCloseTimeout = TimeSpan.FromMinutes(5) });
}
catch (Exception e) when (TemporalException.IsCanceledException(e))
{
// The "when" clause above is because we only want to apply the logic to cancellation, but
// this kind of cleanup could be done on any/all exceptions too.
Workflow.Logger.LogError(e, "Cancellation occurred, performing cleanup");

// Call cleanup activity. If this throws, it will swallow the original exception which we
// are ok with here. This could be changed to just log a failure and let the original
// cancellation continue. We use a different cancellation token since the default one on
// Workflow.CancellationToken is now marked cancelled.
using var detachedCancelSource = new CancellationTokenSource();
await Workflow.ExecuteActivityAsync(
(MyActivities a) => a.MyCancellationCleanupActivity(),
new()
{
ScheduleToCloseTimeout = TimeSpan.FromMinutes(5),
CancellationToken = detachedCancelSource.Token;
});

// Rethrow the cancellation
throw;
}
}

Handle Cancellation in an Activity

How to handle a Cancellation in an Activity using the Temporal .NET SDK

Ensure that the Activity is Heartbeating to receive the Cancellation request and stop execution. Also make sure that the Heartbeat Timeout is set on the Activity Options when calling from the Workflow. An Activity Cancellation Request cancels the CancellationToken on the ActivityExecutionContext.

[Activity]
public async Task MyActivityAsync()
{
// This is a naive loop simulating work, but similar heartbeat/cancellation logic applies to
// other scenarios as well
while (true)
{
// Send heartbeat
ActivityExecutionContext.Current.Heartbeat();

// Do some work, passing the cancellation token
await Task.Delay(1000, ActivityExecutionContext.Current.CancellationToken);
}
}

Request Cancellation

How to request Cancellation of a Workflow using the Temporal .NET SDK

Use CancelAsync on the WorkflowHandle to cancel a Workflow Execution.

// Get a workflow handle by its workflow ID. This could be made specific to a run by passing run ID.
// This could also just be a handle that is returned from StartWorkflowAsync instead.
var handle = myClient.GetWorkflowHandle("my-workflow-id");

// Send cancellation. This returns when cancellation is received by the server. Wait on the handle's
// result to wait for cancellation to be applied.
await handle.CancelAsync();

How to request Cancellation of an Activity in .NET using the Temporal .NET SDK

By default, Activities are automatically cancelled when the Workflow is cancelled since the workflow cancellation token is used by activities by default. To issue a cancellation explicitly, a new cancellation token can be created.

[WorkflowRun]
public async Task RunAsync()
{
// Create a source linked to workflow cancellation. A new source could be created instead if we
// didn't want it associated with workflow cancellation.
using var cancelActivitySource = CancellationTokenSource.CreateLinkedTokenSource(
Workflow.CancellationToken);

// Start the activity. Whether this workflow waits on the activity to handle the cancellation
// or not is dependent upon the CancellationType option. We leave the default here which sends
// the cancellation but does not wait on it to be handled.
var activityTask = Workflow.ExecuteActivityAsync(
(MyActivities a) => a.MyNormalActivity(),
new()
{
ScheduleToCloseTimeout = TimeSpan.FromMinutes(5),
CancellationToken = cancelActivitySource.Token;
});
activityTask.Start();

// Wait 5 minutes, then cancel it
await Workflow.DelayAsync(TimeSpan.FromMinutes(5));
cancelActivitySource.Cancel();

// Wait on the activity which will throw cancellation which will fail the workflow
await activityTask;
}

Termination

How to Terminate a Workflow Execution in .NET using the Temporal .NET SDK

To Terminate a Workflow Execution in .NET, use the TerminateAsync() method on the Workflow handle.

// Get a workflow handle by its workflow ID. This could be made specific to a run by passing run ID.
// This could also just be a handle that is returned from StartWorkflowAsync instead.
var handle = myClient.GetWorkflowHandle("my-workflow-id");

// Terminate
await handle.TerminateAsync();

Workflow Executions can also be Terminated directly from the WebUI. In this case, a custom note can be logged from the UI when that happens.