BroadcastCopyBlock for TPL Dataflow with guaranteed delivery

后端 未结 2 1475
余生分开走
余生分开走 2021-01-13 14:22

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

2条回答
  •  小鲜肉
    小鲜肉 (楼主)
    2021-01-13 14:43

    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.

提交回复
热议问题