Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for .NET CancellationTokens #9127

Merged
merged 23 commits into from
Mar 20, 2025

Conversation

koenbeuk
Copy link
Contributor

@koenbeuk koenbeuk commented Aug 26, 2024

This PR allows for grain methods to be cancelled using a CancellationToken. The implementation is loosely based on the existing GrainCancellationToken support that is already available.

  1. CodeGen detects the use of a CancellationToken in a grain interface method
  2. If multiple CancellationTokens are used within the same grain interface method then ORLEANS0109 diagnostic is raised
  3. The generated proxy throws early if cancellation is requested. Otherwise it will register for cancellation and sends a one-way message to ICancellableInvokableGrainExtension.CancelRemoteToken to mark this token as canceled
  4. CancellableInvokableGrainExtension looks up the grains ICancellationRuntime component to mark the token as canceled
  5. The generated invokable implements an additional interface: ICancellableInvokable which exposes the method: GetCancellableTokenId
  6. Each instance of a CancellableInvokable sets a cancellableTokenId as Guid.NewGuid()
  7. The InvokeInner implementation on the invokable can optionally interact with an ICancellationRuntime to track cancellation of this invokable.

Once the invokable completes, its CancellationTokenSource obtained through the ICancellationRuntime is always Canceled

Fixes: #8958

Microsoft Reviewers: Open in CodeFlow

@koenbeuk
Copy link
Contributor Author

There is a regression with supporting IAsyncEnumerable with this PR. Will fix that regression and in turn, try and fix #8958

@koenbeuk koenbeuk changed the title Support for .NET CancellationTokens [WIP] Support for .NET CancellationTokens Aug 27, 2024
@koenbeuk koenbeuk changed the title [WIP] Support for .NET CancellationTokens Support for .NET CancellationTokens Aug 27, 2024
@ReubenBond ReubenBond self-assigned this Aug 27, 2024
@koenbeuk koenbeuk changed the title Support for .NET CancellationTokens [WIP] Support for .NET CancellationTokens Aug 28, 2024
@koenbeuk koenbeuk changed the title [WIP] Support for .NET CancellationTokens Support for .NET CancellationTokens Sep 2, 2024
@kzu
Copy link
Contributor

kzu commented Oct 24, 2024

This would be super helpful 🙏

@ReubenBond
Copy link
Member

@koenbeuk is there anything remaining here or is this ready for review? Apologies for the delay

@ReubenBond ReubenBond requested a review from Copilot February 6, 2025 14:56
Copy link

@Copilot 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.

Copilot reviewed 6 out of 21 changed files in this pull request and generated 2 comments.

Files not reviewed (15)
  • src/Orleans.Runtime/Cancellation/CancellableInvokableGrainExtension.cs: Evaluated as low risk
  • src/Orleans.Serialization/Invocation/ICancellationRuntime.cs: Evaluated as low risk
  • src/Orleans.Runtime/Hosting/DefaultSiloServices.cs: Evaluated as low risk
  • src/Orleans.Runtime/Core/InsideRuntimeClient.cs: Evaluated as low risk
  • src/Orleans.Runtime/Cancellation/CancellationRuntime.cs: Evaluated as low risk
  • test/Grains/TestGrainInterfaces/IGenericInterfaces.cs: Evaluated as low risk
  • src/Orleans.Core/Runtime/SharedCallbackData.cs: Evaluated as low risk
  • test/Orleans.Serialization.UnitTests/BuiltInCodecTests.cs: Evaluated as low risk
  • src/Orleans.CodeGenerator/LibraryTypes.cs: Evaluated as low risk
  • src/Orleans.Core/Runtime/OutsideRuntimeClient.cs: Evaluated as low risk
  • src/Orleans.CodeGenerator/SerializerGenerator.cs: Evaluated as low risk
  • src/Orleans.CodeGenerator/Model/InvokableMethodDescription.cs: Evaluated as low risk
  • src/Orleans.CodeGenerator/AnalyzerReleases.Unshipped.md: Evaluated as low risk
  • src/Orleans.CodeGenerator/InvokableGenerator.cs: Evaluated as low risk
  • test/Grains/TestGrains/GenericGrains.cs: Evaluated as low risk
Comments suppressed due to low confidence (2)

src/Orleans.Serialization/Invocation/ICancellableInvokable.cs:21

  • [nitpick] The method name 'GetCancellableTokenId' is ambiguous. It should be renamed to 'GetCancellationTokenId' for better clarity.
Guid GetCancellableTokenId();

src/Orleans.Core/Runtime/CallbackData.cs:34

  • The SubscribeForCancellation method introduces new behavior that should be covered by tests to ensure it works correctly under various scenarios (e.g., token already canceled, token gets canceled after registration).
public void SubscribeForCancellation(IInvokable invokable)

@ReubenBond ReubenBond force-pushed the native-cancellation-tokens branch from fe48efd to b86f46e Compare March 17, 2025 22:53
@ReubenBond
Copy link
Member

(rebased on main)

@ReubenBond ReubenBond force-pushed the native-cancellation-tokens branch from b86f46e to 2c5355a Compare March 18, 2025 21:54
@ReubenBond
Copy link
Member

@koenbeuk thank you for great work on this PR and for your patience. I have pushed some updates to implement the identification strategy we discussed (using sender's GrainId + MessageId).

I added two config options on MessagingOptions (i.e, SiloMessagingOptions/ClientMessagingOptions):

/// <summary>
/// Whether request cancellation should be attempted when a request times out.
/// </summary>
/// <remarks>
/// Request cancellation may involve sending a cancellation message to the silo which hosts the target grain.
/// Defaults to <see langword="true"/>.
/// </remarks>
public bool CancelRequestOnTimeout { get; set; } = true;

/// <summary>
/// Whether local calls should be cancelled immediately when cancellation is signaled (<see langword="false"/>)
/// rather than waiting for callees to acknowledge cancellation before a call is considered cancelled (<see langword="true"/>).
/// </summary>
/// <remarks>
/// Defaults to <see langword="false"/>.
/// </remarks>
public bool WaitForCancellationAcknowledgement { get; set; }

CancelRequestOnTimeout sends a cancellation signal in two cases:

  • When the request times out and CallbackData.OnTimeout() is called.
  • When a status message is received for an unknown request.

I'm not sure that we necessarily need to make these things configurable, but I erred on this side.

I changed the codegen to include a CancellationTokenSource object on the IInvokable implementation and to add a TryCancel() method to cancel it if the method accepts a CancellationToken. I excluded CancellationToken args from serialization.

I updated the IAsyncEnumerable impl to take advantage of this CancellationToken support.

I implemented batching for cancellation to hopefully reduce the impact of large volumes of cancellations on the wire - one might expect cancellation rates to increase when load increases. If that also leads to a significant increase in network traffic / CPU load, that could make the situation worse, so I felt that some batching was warranted.

CancellationToken parameters can be added to existing methods (as the last argument) without breaking forward or backwards compatibility.

@ReubenBond ReubenBond force-pushed the native-cancellation-tokens branch from 90a78cb to f346034 Compare March 20, 2025 13:51
@ReubenBond ReubenBond merged commit df44418 into dotnet:main Mar 20, 2025
24 of 25 checks passed
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.

Cannot cancel an IAsyncEnumerable
4 participants