2

Can I/Should I use reactive extensions for this? Basically I have an ESB which I want to monitor for messages (which is essentially where my hot observable sits atop) , and I want to create a bunch of subscribers which will block/pause in the thread they are created in only when a certain condition is met and /or a timeout occurs.

I know I can achieve this with Tasks/TaskCompletionSource and a Cancellation token but I thought that RX seemed like a nice fit.

EDIT: The timeout is not on the observable but should be at the subscribers, where they can unsubscribe and dispose of themselves once a timeout/condition is met, which ever comes first.

EDIT 2: The subscriber(s) and the observable will likely be processed on different threads - but not necessarily. If using async/await on the subscriber I want to be able to pause/block execution where the subscriber is situated. Basically, signalling completion of some work

What I am after is leveraging subscriber lifetime managment so I dont have to do anything. IConnectableObservable seemed to offer some promise in this area.

Perhaps this is square peg, round hole territory.

brumScouse
  • 3,166
  • 1
  • 24
  • 38
  • What does it mean that a subscriber blocks/pauses ? Stops receiving notifications ? – supertopi Nov 22 '16 at 15:52
  • The subscriber will be notifiable, and - upon notification (i.e. via OnNext) - if a paritcular condition is met the subscriber will be disposed/disconnected from the Observable. – brumScouse Nov 22 '16 at 16:06

1 Answers1

3

I think this is what you're after, not entirely sure. Sample code is always a helpful clarifier. The trick is to put your operators not at the source, but by the subscriptions:

async void Main()
{
    var hotObservable = new Subject<string>();

    Func<string, bool> sub1_Condition = s => s != "Disconnect Sub1";
    var subscription1 = hotObservable
        .Timeout(TimeSpan.FromSeconds(5))
        .TakeWhile(sub1_Condition)
        .Subscribe(s => Console.WriteLine($"Sub 1: {s}"), _ => Console.WriteLine("Sub1 Timeout."), () => Console.WriteLine("Sub1 condition met or source ended."));

    Func<string, bool> sub2_Condition = s => s != "Disconnect Sub2";
    var subscription2 = hotObservable
        .Timeout(TimeSpan.FromSeconds(2))
        .TakeWhile(sub2_Condition)
        .Subscribe(s => Console.WriteLine($"Sub 2: {s}"), _ => Console.WriteLine("Sub2 Timeout."), () => Console.WriteLine("Sub2 condition met or source ended."));

    Func<string, bool> sub3_Condition = s => s != "Disconnect Sub3";
    var subscription3 = hotObservable
        .Timeout(TimeSpan.FromSeconds(7))
        .TakeWhile(sub2_Condition)
        .Subscribe(s => Console.WriteLine($"Sub 3: {s}"), _ => Console.WriteLine("Sub3 Timeout."), () => Console.WriteLine("Sub3 condition met or source ended."));

    hotObservable.OnNext("Hello");
    hotObservable.OnNext("Disconnect Sub1");

    await Task.Delay(TimeSpan.FromSeconds(3));

    hotObservable.OnNext("Just Sub 3 should be left");
    hotObservable.OnCompleted();
}

This produces the following output:

Sub 1: Hello
Sub 2: Hello
Sub 3: Hello
Sub1 condition met or source ended.
Sub 2: Disconnect Sub1
Sub 3: Disconnect Sub1
Sub2 Timeout.
Sub 3: Just Sub 3 should be left
Sub3 condition met or source ended.
Shlomo
  • 14,102
  • 3
  • 28
  • 43
  • You know what! I think this is v.close to what I want. I agree code would help. I will code this up (I am implementing the Task, Tcs variant) but for me this solution is cleaner because of subscription management. Am I making sense? Maybe I'm overplaying the benefits... – brumScouse Nov 23 '16 at 10:40
  • I think? Rx tends to be cleaner than tasks, though less intuitive unless you're used to it. In what scenario does this not work for you? – Shlomo Nov 23 '16 at 13:08
  • Not saying it didnt work, I was simply using an alternative implementation to expedite stuff for our team – brumScouse Nov 23 '16 at 16:26
  • Enclosing this in a factory method, of sorts, and returning a task from a tcs, gives me almost exactly what i need. The only issue i have is that when OnNext is called, the OnNext callback in the subscriber doesnt appear to be being called, i think this might be down to delay in subscription creation. I think I saw a way to ensure subscription creation being a requisite. I control the incoming stream by initiating proceedings with a command. Perhaps an ordering thing. – brumScouse Nov 23 '16 at 21:35