Search code examples
c#task-parallel-librarytpl-dataflow

OperationCanceledException thrown in tpl dataflow block gets swallowed


For some reason when an OperationCanceledException gets thrown inside an IDataflowBlock, the block does not propagate this exception to its IDataflowBlock.Completion task. Running the code sample below returns an unexpected IDataflowBlock.Completion.Status == TaskStatus.RanToCompletion.

However, if the thrown exception type in the block is changed to an ArgumentNullException, the IDataflowBlock.Completion.Status changes to TaskStatus.Faulted and the exception is saved in its InnerException property.

Any ideas why OperationCanceledException is getting swallowed?

[TestFixture]
public class TplDataBlockExceptionTest
{
    [Test]
    public void ShouldThrowException()
    {
        // Arrange
        var block = new TransformBlock<int, string>(i =>
        {
            throw new OperationCanceledException();
            return i.ToString();
        });

        // Act

        block.Post(1);
        block.Complete();

        try
        {
            block.Completion.Wait();
        }
        catch (Exception)
        {
            // ignored
        }

        // Assert

        Assert.That(block.Completion.IsFaulted);
    }
}

Solution

  • I was able to reach Stephen Toub at Microsoft and he was able to confirm that this behavior is by design:

    https://github.com/dotnet/corefx/blob/master/src/System.Threading.Tasks.Dataflow/src/Blocks/TransformBlock.cs#L186-L190

    https://github.com/dotnet/corefx/blob/master/src/System.Threading.Tasks.Dataflow/src/Internal/Common.cs#L152-L175