0

We use BufferBlocks to build a small simulation tool where we want to find areas that takes a long time to complete. Producers and Consumers of the blocks will essentially sleep for x amount of time and then post a message to another block. We decided to use an Observer pattern. Howver, I see some behavior I did not expect. Whenever the OnNext method of the observers is called the BufferBlock is empty (Count == 0). This is problematic as I want only 1 observer to be able to fetch the value from the queue. Is there a way to change this behavior? If not, how should I handle consumption from the BufferBlocks?

Currently I want to be able to do something similar to post the messages and have all Observers try to fetch it:

public void OnNext(Object value)
{
    var res =this.AsConsumer().ConsumeQueue.ReceiveAsync().Result;
    Thread.Sleep(this.TimeToConsume );
    ProduceQueue.Post(someOtherValue);
}

I have written some tests to show the behavior of the BufferBlock.

[Test]
public void 
WhenObservingMocks_CallsOnNextForAllMocks()
{
    var firstObserver = new Mock<IObserver<int>>();
    var secondObserver = new Mock<IObserver<int>>();
    var block = new BufferBlock<int>();

    block.AsObservable().Subscribe(firstObserver.Object);
    block.AsObservable().Subscribe(secondObserver.Object);

    block.Post(2);
    Thread.Sleep(TimeSpan.FromMilliseconds(50));
    firstObserver.Verify(e => e.OnNext(It.IsAny<int>()), Times.Once); 
    secondObserver.Verify(e => e.OnNext(It.IsAny<int>()), Times.Once);
}

[Test]
public void 
    WhenHavingObservers_DoesConsumesTheElementFromQueue()
{
    var firstObserver = new Mock<IObserver<int>>();
    var secondObserver = new Mock<IObserver<int>>();
    var block = new BufferBlock<int>();

    block.AsObservable().Subscribe(firstObserver.Object);
    block.AsObservable().Subscribe(secondObserver.Object);

    block.Post(2);
    Assert.Zero(block.Count);
}

[Test]
public void 
    WhenPostingOnce_CanOnlyReceiveOnce()
{
    var block = new BufferBlock<int>();
    block.Post(2);
    Assert.True(block.TryReceive(out int _));
    Assert.False(block.TryReceive(out int _));
}
Bruno Volpato
  • 1,382
  • 10
  • 18
  • FWIW personally I've given up with mixing Dataflow and Rx. There are too many rough corners, and too many traps to fall in. From a [recent GitHub issue](https://github.com/dotnet/runtime/issues/70481 "The WriteOnceBlock behaves unexpectedly with AsObservable"): *"at present WriteOnceBlock composability with AsObservable isn't perfect."* – Theodor Zoulias Dec 23 '22 at 07:48

0 Answers0