I would be glad for some input on the following implementation of a BroadcastCopyBlock
in TPL Dataflow, which copies a received message to all consumers, that r
I just want to add to VMAtm's excellent answer that in BoundedWrapperInfiniteCase
, you can manually propagate the completion. Add the following lines before the call to broadcast.SendAsync()
then wait for both actions to complete to make the action wrappers complete the inner actions:
slowActionWrapper.Completion.ContinueWith(t =>
{
if (t.IsFaulted) ((IDataflowBlock)slowAction).Fault(t.Exception);
else slowAction.Complete();
});
fastActionWrapper.Completion.ContinueWith(t =>
{
if (t.IsFaulted) ((IDataflowBlock)fastAction).Fault(t.Exception);
else fastAction.Complete();
});
e.g.
var broadcast = new BroadcastBlock(i => i);
var fastAction = new ActionBlock(i => Console.WriteLine($"FAST Wrapper Block: {i}"));
var slowAction = new ActionBlock(i =>
{
Thread.Sleep(2000);
Console.WriteLine($"SLOW Wrapper Block: {i}");
}, new ExecutionDataflowBlockOptions { BoundedCapacity = 2 });
var fastActionWrapper = new ActionBlock(i => fastAction.SendAsync(i));
var slowActionWrapper = new ActionBlock(i => slowAction.SendAsync(i));
broadcast.LinkTo(slowActionWrapper, new DataflowLinkOptions { PropagateCompletion = true });
broadcast.LinkTo(fastActionWrapper, new DataflowLinkOptions { PropagateCompletion = true });
// Manually propagate completion to the inner actions
slowActionWrapper.Completion.ContinueWith(t =>
{
if (t.IsFaulted) ((IDataflowBlock)slowAction).Fault(t.Exception);
else slowAction.Complete();
});
fastActionWrapper.Completion.ContinueWith(t =>
{
if (t.IsFaulted) ((IDataflowBlock)fastAction).Fault(t.Exception);
else fastAction.Complete();
});
for (var i = 0; i < 3; ++i)
broadcast.SendAsync(i);
broadcast.Complete();
// Wait for both inner actions to complete
Task.WaitAll(slowAction.Completion, fastAction.Completion);
The output will be the same as in VMAtm's answer, but all tasks will properly complete.