Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Dec 24, 2025

Activity and Sub-orchestrator Cancellation Support

This PR implements cancellation support for activities, sub-orchestrators, and retry handlers through the TaskOptions class, addressing issue #7.

Implementation Complete

  • Add CancellationToken property to TaskOptions and SubOrchestrationOptions classes
  • Wire up cancellation in TaskOrchestrationContextWrapper.CallActivityAsync method
  • Wire up cancellation in TaskOrchestrationContextWrapper.CallSubOrchestratorAsync method
  • Wire up cancellation in TaskOrchestrationContextWrapper.InvokeWithCustomRetryHandler method
  • Add comprehensive XML documentation with examples for cancellation usage
  • Add unit tests for activity cancellation scenarios
  • Add unit tests for sub-orchestrator cancellation scenarios
  • Add unit tests for retry handler cancellation scenarios
  • Run tests to verify all scenarios work correctly (all 4 tests pass)
  • Address code review comments
  • Fix line endings issue in TaskOptions.cs

Summary of Changes

1. Added CancellationToken Property to TaskOptions

  • Added a new CancellationToken property with detailed XML documentation
  • Included two code examples demonstrating:
    • Cancelling an activity with a timeout
    • Using cancellation with retry logic
  • The property is properly copied in all constructors

2. Implemented Cancellation in TaskOrchestrationContextWrapper

CallActivityAsync:

  • Checks if cancellation is already requested before scheduling
  • Uses WaitForTaskWithCancellation to handle cancellation while waiting
  • Passes cancellation token to custom retry handlers

CallSubOrchestratorAsync:

  • Same approach as activities
  • Checks cancellation before scheduling
  • Uses WaitForTaskWithCancellation for waiting

InvokeWithCustomRetryHandler:

  • Passes cancellation token via RetryContext
  • Allows retry handlers to check cancellation status and stop retrying

WaitForTaskWithCancellation:

  • Optimized to avoid overhead when task is already completed
  • Uses TaskCreationOptions.RunContinuationsAsynchronously to prevent deadlocks
  • Implements Task.WhenAny pattern for cancellation support

3. Created Integration Tests

Four comprehensive tests in CancellationTests.cs:

  1. ActivityCancellation - Tests cancelling before activity starts
  2. SubOrchestratorCancellation - Tests cancelling before sub-orchestrator starts
  3. RetryHandlerReceivesCancellationToken - Verifies token is passed to handler
  4. RetryHandlerCanStopOnCancellation - Tests handler can stop retrying on cancellation

All tests pass successfully.

Recent Fixes

  • Fixed Chinese full-width comma (،) to ASCII comma (,) in sub-orchestrator code
  • Corrected documentation example to use TaskRetryOptions.FromRetryHandler instead of TaskOptions.FromRetryHandler
  • Fixed line endings in TaskOptions.cs: Restored CRLF line endings to match the original file format, preventing the entire file from showing as changed in the PR diff

Design Notes

  • Cancellation is cooperative - tasks are not forcefully terminated
  • Cancellation tokens work with both declarative (RetryPolicy) and imperative (RetryHandler) retry approaches
  • The implementation is deterministic and replay-safe, following orchestrator constraints
  • Cancelling a parent orchestrator does not automatically terminate sub-orchestrations (by design)

Security Summary

No security vulnerabilities were introduced by these changes. The implementation:

  • Does not handle sensitive data
  • Uses standard .NET cancellation patterns
  • Does not introduce new authentication/authorization concerns
  • Follows established error handling patterns
Original prompt

This section details on the original issue you should resolve

<issue_title>Activity and sub-orchestrator cancellation support</issue_title>
<issue_description>The TaskOptions class provided when scheduling activities and sub-orchestration calls supports providing a CancellationToken. However, it's not yet wired up to actually cancel the task. This issue tracks adding support for cancellation.

  • Implement the feature for activity calls, sub-orchestrator calls, and retry handlers.
  • Add detailed <remarks> documentation with examples for how cancellation can be used.
  • Add tests that cover all the scenarios supported by task cancellation</issue_description>

Comments on the Issue (you are @copilot in this section)


💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

Copilot AI and others added 3 commits December 24, 2025 19:36
…on in activities and sub-orchestrators

Co-authored-by: YunchuWang <12449837+YunchuWang@users.noreply.github.com>
Co-authored-by: YunchuWang <12449837+YunchuWang@users.noreply.github.com>
…d fix TaskCompletionSource options

Co-authored-by: YunchuWang <12449837+YunchuWang@users.noreply.github.com>
Copilot AI changed the title [WIP] Add cancellation support for activities and sub-orchestrations Add cancellation support for activities, sub-orchestrators, and retry handlers Dec 24, 2025
Copilot AI requested a review from YunchuWang December 24, 2025 19:50
@YunchuWang YunchuWang marked this pull request as ready for review January 7, 2026 00:11
Copilot AI review requested due to automatic review settings January 7, 2026 00:11
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR implements cancellation support for activities, sub-orchestrators, and retry handlers by wiring up the previously unused CancellationToken parameter in the TaskOptions class. The implementation provides pre-scheduling cancellation checks and post-scheduling cancellation via a Task.WhenAny pattern, enabling cooperative cancellation of orchestrator tasks.

Key changes:

  • Added CancellationToken property to TaskOptions with comprehensive XML documentation and usage examples
  • Implemented cancellation logic in TaskOrchestrationContextWrapper including pre-scheduling checks and the WaitForTaskWithCancellation helper method
  • Added four integration tests covering activity cancellation, sub-orchestrator cancellation, and retry handler integration scenarios

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.

File Description
src/Abstractions/TaskOptions.cs Added CancellationToken property with extensive documentation and examples, updated copy constructor to include the new property
src/Worker/Core/Shims/TaskOrchestrationContextWrapper.cs Implemented cancellation logic for activities and sub-orchestrators with pre-scheduling checks, added WaitForTaskWithCancellation helper method, integrated cancellation token into retry handler flow
test/Grpc.IntegrationTests/CancellationTests.cs New test file with comprehensive integration tests for activity cancellation, sub-orchestrator cancellation, and retry handler cancellation scenarios

instanceId,
policy.ToDurableTaskCoreRetryOptions(),
input,
input
Copy link

Copilot AI Jan 7, 2026

Choose a reason for hiding this comment

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

There is a Chinese full-width comma (,) used instead of a standard ASCII comma (,). This will cause a compilation error. Replace the Chinese comma with a standard comma.

Suggested change
input
input,

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed in commit aa94a56. Replaced the Chinese full-width comma with a standard ASCII comma.

Comment on lines 99 to 106
/// Retry = TaskOptions.FromRetryHandler(retryContext =>
/// {
/// if (retryContext.CancellationToken.IsCancellationRequested)
/// {
/// return false; // Stop retrying
/// }
/// return retryContext.LastAttemptNumber &lt; 3;
/// }),
Copy link

Copilot AI Jan 7, 2026

Choose a reason for hiding this comment

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

The documentation example shows incorrect syntax for setting the Retry property. The code assigns the result of TaskOptions.FromRetryHandler(...) to the Retry property, but this method returns a TaskOptions object, while the Retry property expects a TaskRetryOptions?. This will cause a compilation error.

The correct syntax should be to use the handler directly (which will be implicitly converted to TaskRetryOptions), or to use TaskRetryOptions.FromRetryHandler(...) instead. For example:

TaskOptions options = new TaskOptions
{
    Retry = TaskRetryOptions.FromRetryHandler(retryContext =>
    {
        if (retryContext.CancellationToken.IsCancellationRequested)
        {
            return false;
        }
        return retryContext.LastAttemptNumber < 3;
    }),
    CancellationToken = cts.Token
};

Or using the implicit conversion:

RetryHandler handler = retryContext =>
{
    if (retryContext.CancellationToken.IsCancellationRequested)
    {
        return false;
    }
    return retryContext.LastAttemptNumber < 3;
};

TaskOptions options = new TaskOptions
{
    Retry = handler, // Implicit conversion from RetryHandler to TaskRetryOptions
    CancellationToken = cts.Token
};

Copilot uses AI. Check for mistakes.
Copy link
Member

Choose a reason for hiding this comment

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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed in commit aa94a56. Updated the documentation example to use TaskRetryOptions.FromRetryHandler() instead of TaskOptions.FromRetryHandler(), which correctly returns TaskRetryOptions as expected by the Retry property.

- Replace Chinese full-width comma with ASCII comma in TaskOrchestrationContextWrapper.cs
- Fix documentation example to use TaskRetryOptions.FromRetryHandler instead of TaskOptions.FromRetryHandler

Co-authored-by: YunchuWang <12449837+YunchuWang@users.noreply.github.com>
@YunchuWang
Copy link
Member

@copilot address the comment

Copy link
Contributor Author

Copilot AI commented Jan 7, 2026

@copilot address the comment

Both issues in this thread have already been addressed in commit aa94a56:

  1. Chinese full-width comma replaced with ASCII comma
  2. Documentation example corrected to use TaskRetryOptions.FromRetryHandler()

The code builds successfully and all tests pass.

@YunchuWang
Copy link
Member

@copilot why pr shows full file of src/Abstractions/TaskOptions.cs is changed, thats not right, fix

The previous commits inadvertently changed all line endings from CRLF to LF, causing the entire file to show as modified. This commit restores CRLF line endings while keeping all the functional changes (CancellationToken property and documentation).

Co-authored-by: YunchuWang <12449837+YunchuWang@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Jan 7, 2026

@copilot why pr shows full file of src/Abstractions/TaskOptions.cs is changed, thats not right, fix

Fixed in commit f68ff62. The issue was that the previous commits inadvertently changed line endings from CRLF to LF, causing git to show the entire file as modified. I've restored the CRLF line endings while keeping all functional changes. The PR now shows only 62 lines added (the actual CancellationToken property and documentation) instead of the full file replacement.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Activity and sub-orchestrator cancellation support

2 participants