Jason Dicker
Jason Dicker

Reputation: 125

TPL Dataflow not completing with multiple targets

I have a BufferBlock linked to two Target Blocks. The dataflow does not complete. I have followed the suggestions from this post, but I can't get the completion propagation right.

Any help would be appreciated.

// define blocks
var bufferBlock = new BufferBlock<int>(); 

var actionBlock1 = new TransformBlock<int, int>(i =>
{
    Console.WriteLine($"actionBlock1: {i}");
    return i;
});
var actionBlock2 = new ActionBlock<int>(i =>
{
    Console.WriteLine($"actionBlock2: {i}");
});

// link blocks 
bufferBlock.LinkTo(actionBlock1, i => i == 1);
bufferBlock.LinkTo(actionBlock2, i => i == 2);
bufferBlock.LinkTo(DataflowBlock.NullTarget<int>()); 

// push to block 
var items = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
foreach (var i in items)
{
    bufferBlock.Post(i);
}

// wait for all operations to complete
bufferBlock.Complete();

// NB: block will only propagate completion to one block regardless of how many blocks are linked. This even applies to the BroadcastBlock that broadcasts messages, it will not broadcast completion. In that case you can configure a continuation on the Completion Task
// see https://stackoverflow.com/questions/47310402/tpl-complete-vs-completion/47311537#47311537
var bufferBlockCompletion = bufferBlock.Completion.ContinueWith(tsk =>
{
    if (!tsk.IsFaulted)
    {
        actionBlock1.Complete();
        actionBlock2.Complete();
    }
    else
    {
        ((IDataflowBlock)actionBlock1).Fault(tsk.Exception);
        ((IDataflowBlock)actionBlock2).Fault(tsk.Exception);
    }
});

await Task.WhenAll(bufferBlockCompletion, actionBlock1.Completion, actionBlock2.Completion);

Upvotes: 1

Views: 470

Answers (1)

JSteward
JSteward

Reputation: 7091

actonBlock1 is a TransformBlock that is not linked to anything. Any items that the block produces will remain in its output buffer, in this cas only the number 1. With items stuck in the output the block can never complete. You can fix that a couple of different ways depending on what exactly you need.

1) Change the TransformBlock to an ActionBlock

2) Link the TransformBlock to a NullTarget or another block.

Upvotes: 3

Related Questions