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

[release/9.0] Check CancellationToken before TimeSpan in TimeProviderTaskExtensions #107416

Merged
merged 2 commits into from
Sep 6, 2024

Conversation

github-actions[bot]
Copy link
Contributor

@github-actions github-actions bot commented Sep 5, 2024

Backport of #107009 to release/9.0

/cc @tarekgh @brantburnett

Customer Impact

  • Customer reported
  • Found internally

[Select one or both of the boxes. Describe how this issue impacts customers, citing the expected and actual behaviors and scope of the issue. If customer-reported, provide the issue number.]

Users utilizing TimeProvider and calling Delay or WaitAsync may encounter inconsistent task cancellation behavior between .NET 8.0+ and earlier versions. In .NET 8.0 and later, the task status will be canceled, while on down-level versions, the task could be marked as completed if the time expires, even if it was canceled. This discrepancy can lead to apps behaving differently depending on the .NET version they're running on.

Regression

  • Yes
  • No

[If yes, specify when the regression was introduced. Provide the PR or commit if known.]

Testing

[How was the fix verified? How was the issue missed previously? What tests were added?]

Added new test to catch the failing issue and passed all regression tests too.

Risk

[High/Medium/Low. Justify the indication by mentioning how risks were measured and addressed.]

Low, there is no real change more than switching the order task status checking before completing the task. we used to check the time expiration then we check the cancellation. Now, we check cancellation first and then we check the time expiration. The change only affect apps when running on down-levels. i.e. shouldn't affect apps running on .NET 8 or 9

IMPORTANT: If this backport is for a servicing release, please verify that:

  • The PR target branch is release/X.0-staging, not release/X.0.

  • If the change touches code that ships in a NuGet package, you have added the necessary package authoring and gotten it explicitly reviewed.

…sions

This makes the down-level behavior for Delay and WaitAsync match the
behavior in .NET 8 and later, prefering to return a Canceled task over
a Completed task or TimeoutException when the TimeSpan is Zero and the
CancellationToken is already Canceled.

Fixes #106996
@tarekgh tarekgh self-assigned this Sep 5, 2024
@tarekgh tarekgh added this to the 9.0.0 milestone Sep 5, 2024
@tarekgh tarekgh added the Servicing-consider Issue for next servicing release review label Sep 5, 2024
Copy link
Contributor

Tagging subscribers to this area: @dotnet/area-system-datetime
See info in area-owners.md if you want to be subscribed.

@tarekgh
Copy link
Member

tarekgh commented Sep 5, 2024

CC @artl93 @ericstj @stephentoub

@stephentoub
Copy link
Member

What's the motivation for getting this into .NET 9? It's pretty minor, and pre-existing, no?

@tarekgh
Copy link
Member

tarekgh commented Sep 5, 2024

What's the motivation for getting this into .NET 9? It's pretty minor, and pre-existing, no?

It was reported by someone who ran into this issue, and I am not aware of any workaround. Do you have a good suggestion for what to do for those who run into it? do you see any risk taking this change?

@brantburnett
Copy link
Contributor

What's the motivation for getting this into .NET 9? It's pretty minor, and pre-existing, no?

FWIW, I found this bug while trying to integrate Microsoft.Bcl.TimeProvider into an existing NuGet package that supports down-level targets. I can apply a workaround, which is to call CancellationToken.ThrowIfCancellationRequested() before calling the two affected methods. This provides basically equivalent behavior. However, this does add a performance penalty in the hot path because the token will be checked twice, once by the library code and again within Microsoft.Bcl.TimeProvider. I'd prefer to not need to apply a workaround for another year, but I understand if it's considered not worth it.

@stephentoub
Copy link
Member

Do you have a good suggestion for what to do for those who run into it?

Just check token.IsCancellationRequested, either directly or indirectly via ThrowIfCancellationRequested.

do you see any risk taking this change?

No, it's low risk. We're just at a point in the cycle where there generally needs to be a strong justification for any churn.

@ericstj
Copy link
Member

ericstj commented Sep 5, 2024

I was viewing this as a compat issue in a recently introduced feature which is why I brought it into 9.0.

@stephentoub
Copy link
Member

stephentoub commented Sep 5, 2024

Ok, it's up to you. Generally though this is a non-deterministic scenario, with a race with cancellation being requested, so I don't see this as being particularly impactful.

@artl93 artl93 added Servicing-approved Approved for servicing release and removed Servicing-consider Issue for next servicing release review labels Sep 5, 2024
@ericstj ericstj merged commit 27ee86c into release/9.0 Sep 6, 2024
86 of 91 checks passed
@jkotas jkotas deleted the backport/pr-107009-to-release/9.0 branch September 18, 2024 21:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-System.DateTime Servicing-approved Approved for servicing release
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants