Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 22 additions & 1 deletion src/ActivityHeartbeatingCancellation/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,25 @@ Then in another terminal, run the workflow from this directory:

dotnet run workflow

This will show logs in the worker window of the workflow running.
This will show logs in the worker window of the workflow running.

# Retry + Heartbeat Activity Example

This example demonstrates how to combine **Retry Policies** and **Activity Heartbeats**
in Temporal's .NET SDK.

## What This Sample Shows
- How to configure retry settings for an activity.
Copy link
Member

@cretz cretz Dec 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Heartbeating sample seems unrelated to retry settings that you may want to set whether or not you heartbeat. Is this addition to the sample only for showing that you can set the RetryOptions property? This can be set regardless. I am not sure it makes sense in a heartbeating/cancellation sample to demonstrate that this setting can be set (any more than any other activity option setting).

- How an activity can send heartbeat progress.
- How Temporal detects stalled activities via `HeartbeatTimeout`.

This pattern is useful for:
- Batch processing
- Migration jobs
- Long-running operations
- Resumable workflows

## How to Run

1. Start Temporal locally (`temporalite start`).
2. Run the worker:
Comment on lines +37 to +40
Copy link
Member

@cretz cretz Dec 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems to be incomplete and we don't use "temporalite" (other samples say to look at primary README for prerequisites to setup server)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, agreed. I’ll align this README with other samples by removing the temporalite mention and pointing to the primary README prerequisites for running a Temporal server.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if this really deserves to be a sample though. It's simply showing how to change two defaults for a RetryPolicy property, correct? Not sure it relates to heartbeat/cancellation or that it deserves a sample to show how to set retry policy settings.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the feedback to all comments. Makes sense. I understand the desire to keep the sample narrowly focused.
I’ll close this PR. Appreciate the review and discussion.

Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using Temporalio.Activities;

namespace RetryAndHeartbeat;

public class RetryAndHeartbeatActivity
{
[Activity]
public async Task<string> ProcessAsync(string input)
{
for (int i = 0; i < 5; i++)
{
// Send progress
ActivityExecutionContext.Current.Heartbeat(i);
await Task.Delay(500);
}

return $"Processed: {input}";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using Temporalio.Workflows;

namespace RetryAndHeartbeat;

[Workflow]
public class RetryAndHeartbeatWorkflow
{
[WorkflowRun]
public async Task<string> RunAsync(string input)
{
var options = new ActivityOptions
{
StartToCloseTimeout = TimeSpan.FromSeconds(30),
HeartbeatTimeout = TimeSpan.FromSeconds(5),
RetryPolicy = new()
{
MaximumAttempts = 3,
InitialInterval = TimeSpan.FromSeconds(1),
BackoffCoefficient = 2.0,
MaximumInterval = TimeSpan.FromSeconds(10)
Comment on lines +17 to +20
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two of these are the defaults already, and the other two are just choices a user may make regardless of heartbeating/cancellation.

}
};

return await Workflow.ExecuteActivityAsync(
(RetryAndHeartbeatActivity a) => a.ProcessAsync(input),
options);
}
}