[release/6.0-rc2] Fix corner-case handling of cancellation exception in ForEachAsync...
authorgithub-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Fri, 17 Sep 2021 13:27:49 +0000 (09:27 -0400)
committerGitHub <noreply@github.com>
Fri, 17 Sep 2021 13:27:49 +0000 (09:27 -0400)
commit5631710f574e430f46391dab87310f6e01974813
tree11eab45a2ed3de38b5b610ded9cddcc4e001b2f9
parentc3b2aa436e089c08d55cafe9d40995c0fce8120b
[release/6.0-rc2] Fix corner-case handling of cancellation exception in ForEachAsync (#59237)

* Fix corner-case handling of cancellation exception in ForEachAsync

If code in Parallel.ForEachAsync throws OperationCanceledExceptions containing the CancellationToken passed to the iteration and that token has _not_ had cancellation requested (so why are they throwing with it) and there are no other exceptions, the ForEachAsync will effectively hang after failing to complete the task returned from it.

The issue stems from how we treat cancellation.  If the user-supplied token hasn't been canceled but we have OperationCanceledExceptions for the token passed into the iteration (the "internal" token), it can only have been canceled because an exception occurred.  We filter out these cancellation exceptions, leaving just the exceptions that are deemed to have caused the failure in the first place.  But the code doesn't currently account for the possibility that the developer is (arguably erroneously) throwing such an OperationCanceledException with the internal cancellation token as that root failure. The fix is to only filter out these OCEs if there are other exceptions besides them.

* Stop filtering out cancellation exceptions in Parallel.ForEachAsync

Co-authored-by: Stephen Toub <stoub@microsoft.com>
src/libraries/System.Threading.Tasks.Parallel/src/System/Threading/Tasks/Parallel.ForEachAsync.cs
src/libraries/System.Threading.Tasks.Parallel/tests/ParallelForEachAsyncTests.cs