Implementing correct completion of a retryable block

后端 未结 2 1535
栀梦
栀梦 2021-02-01 01:15

Teaser: guys, this question is not about how to implement retry policy. It\'s about correct completion of a TPL Dataflow block.

This question is mostly

2条回答
  •  慢半拍i
    慢半拍i (楼主)
    2021-02-01 01:30

    Maybe a ManualResetEvent can do the trick for you.

    Add a public property to TransformManyBlock

    private ManualResetEvent _signal  = new ManualResetEvent(false);
    public ManualResetEvent Signal { get { return _signal; } }
    

    And here you go:

    var retries = new HashSet>();
    
    TransformManyBlock, TOutput> target = null;
    target = new TransformManyBlock, TOutput>(
        async message =>
        {
            try
            {
                var result = new[] { await transform(message.Data) };
                retries.Remove(message);
    
                // Sets the state of the event to signaled, allowing one or more waiting threads to proceed
                if(!retries.Any()) Signal.Set(); 
                return result;
            }
            catch (Exception ex)
            {
                message.Exceptions.Add(ex);
                if (message.RetriesRemaining == 0)
                {
                    if (failureHandler != null)
                        failureHandler(message.Exceptions);
    
                    retries.Remove(message);
    
                    // Sets the state of the event to signaled, allowing one or more waiting threads to proceed
                    if(!retries.Any()) Signal.Set(); 
                }
                else
                {
                    retries.Add(message);
                    message.RetriesRemaining--;
    
                    Task.Delay(retryDelay)
                        .ContinueWith(_ => target.Post(message));
                }
                return null;
            }
        }, dataflowBlockOptions);
    
    source.LinkTo(target);
    
    source.Completion.ContinueWith(async _ =>
    {
        //Blocks the current thread until the current WaitHandle receives a signal.
        target.Signal.WaitOne();
    
        target.Complete();
    });
    

    I am not sure where your target.InputCount is set. So at the place you change target.InputCount you can add following code:

    if(InputCount == 0)  Signal.Set();
    

提交回复
热议问题