Notifying asynchronous subject from another observable using Rx .NET - c#

I'm trying to notify listeners who subscribed to Subject _sub from another observable and after that log some message in Do handler. I'm calling OnNext and everything would work fine if _sub wasn't asynchronous. The problem here is that there is no OnNextAsync function which I would await in the first observable. What is the best way to do this?
class Program
{
private static Subject<int> _sub = new Subject<int>();
static void Main(string[] args)
{
_sub.SelectMany(async _ =>
{
Console.WriteLine("SUB START: " + _);
await Task.Delay(3000);
Console.WriteLine("SUB END: " + _);
return 1;
}).Subscribe();
Start();
}
public static void Start()
{
int count = 0;
Observable.Interval(TimeSpan.FromSeconds(5)).Select(x =>
{
Console.WriteLine("START INTERVAL");
_sub.OnNext(count++); //onNext is not awaitable
Console.WriteLine("END INTERVAL");
return 1;
})
.Do(_ => Console.WriteLine("ALL FINISHED"))
.Subscribe();
Console.WriteLine("READLINE");
Console.ReadLine();
}
}
Result:
READLINE
START INTERVAL
SUB START: 0
END INTERVAL
ALL FINISHED
SUB END: 0
Expected result:
READLINE
START INTERVAL
SUB START: 0
SUB END: 0
END INTERVAL
ALL FINISHED

An observable should not rely on the behavior of its observers.
I suggest you rethink the whole thing. What you're doing looks more interactive than reactive.

I'm going to echo Paulo for clarity:
Observables shouldn't care about Observers. While an Observable will wait on its synchronous Observers, it's best to think of this as an accident of implementation. An observable doesn't wait at all on an asynchronous Observer. Either way, the waiting shouldn't be relied upon.
You should really re-think how you're doing this. You're using a reactive library to write interactive code. Probably either the wrong choice of tool or a misuse of the tool.
Your code is littered with Rx code-smells. Think of reactive code as a flowchart. A flowchart of your code would look like spaghetti. It should look more like a binary tree.
This sounds like an XY problem: I would suggest re-phrasing your question with what you're trying to accomplish.

Related

How to make an IObservable<string> from console input

I have tried to write console observable as in the example below, but it doesn't work. There are some issues with subscriptions. How to solve these issues?
static class Program
{
static async Task Main(string[] args)
{
// var observable = Observable.Interval(TimeSpan.FromMilliseconds(1000)).Publish().RefCount(); // works
// var observable = FromConsole().Publish().RefCount(); // doesn't work
var observable = FromConsole(); // doesn't work
observable.Subscribe(Console.WriteLine);
await Task.Delay(1500);
observable.Subscribe(Console.WriteLine);
await new TaskCompletionSource().Task;
}
static IObservable<string> FromConsole()
{
return Observable.Create<string>(async observer =>
{
while (true)
{
observer.OnNext(Console.ReadLine());
}
});
}
}
If I used Observable.Interval, it subscribes two times and I have two outputs for one input. If I used any version of FromConsole, I have one subscription and a blocked thread.
To start with, it is usually best to avoid using Observable.Create to create observables - it's certainly there for that purpose, but it can create observables that don't behave like you think they should because of their blocking nature. As you've discovered!
Instead, when possible, use the built-in operators to create observables. And that can be done in this case.
My version of FromConsole is this:
static IObservable<string> FromConsole() =>
Observable
.Defer(() =>
Observable
.Start(() => Console.ReadLine()))
.Repeat();
Observable.Start effectively is like Task.Run for observables. It calls Console.ReadLine() for us without blocking.
The Observable.Defer/Repeat pair repeatedly calls Observable.Start(() => Console.ReadLine()). Without the Defer it would just call Observable.Start and repeatedly return the one string forever.
That solves that.
Now, the second issue is that you want to see the value from the Console.ReadLine() output by both subscriptions to the FromConsole() observable.
Due to the way Console.ReadLine works, you are getting values from each subscription, but only one at a time. Try this code:
static async Task Main(string[] args)
{
var observable = FromConsole();
observable.Select(x => $"1:{x}").Subscribe(Console.WriteLine);
observable.Select(x => $"2:{x}").Subscribe(Console.WriteLine);
await new TaskCompletionSource<int>().Task;
}
static IObservable<string> FromConsole() =>
Observable
.Defer(() =>
Observable
.Start(() => Console.ReadLine()))
.Repeat();
When I run that I get this kind of output:
1:ddfd
2:dfff
1:dfsdfs
2:sdffdfd
1:sdfsdfsdf
The reason for this is that each subscription starts up a fresh subscription to FromConsole. So you have two calls to Console.ReadLine() they effectively queue and each one only gets each alternate input. Hence the alternation between 1 & 2.
So, to solve this you simply need the .Publish().RefCount() operator pair.
Try this:
static async Task Main(string[] args)
{
var observable = FromConsole().Publish().RefCount();
observable.Select(x => $"1:{x}").Subscribe(Console.WriteLine);
observable.Select(x => $"2:{x}").Subscribe(Console.WriteLine);
await new TaskCompletionSource<int>().Task;
}
static IObservable<string> FromConsole() =>
Observable
.Defer(() =>
Observable
.Start(() => Console.ReadLine()))
.Repeat();
I now get:
1:Hello
2:Hello
1:World
2:World
In a nutshell, it's the combination of the non-blocking FromConsole observable and the use of .Publish().RefCount() that makes this work the way you expect.
The problem is that the Console.ReadLine is a blocking method, so the subscription to the FromConsole sequence blocks indefinitely, so the await Task.Delay(1500); line is never reached. You can solve this problem by reading from the console asynchronously, offloading the blocking call to a ThreadPool thread:
static IObservable<string> FromConsole()
{
return Observable.Create<string>(async observer =>
{
while (true)
{
observer.OnNext(await Task.Run(() => Console.ReadLine()));
}
});
}
You can take a look at this question about why there is no better solution than offloading.
As a side note, subscribing to a sequence without providing an onError handler is not a good idea, unless having the process crash with an unhandled exception is an acceptable behavior for your app. It is especially problematic with sequences produced with Observable.Create<T>(async, because it can lead to weird/buggy behavior like this one: Async Create hanging while publishing observable.
You need to return a observable without the publish. You can then subscribe to it and do your thing further. Here is an example. When I run it i can readline multiple times.
public class Program
{
static void Main(string[] args)
{
FromConsole().Subscribe(x =>
{
Console.WriteLine(x);
});
}
static IObservable<string> FromConsole()
{
return Observable.Create<string>(async observer =>
{
while (true)
{
observer.OnNext(Console.ReadLine());
}
});
}
}

How to wait for multiple C# events?

I would like find out a good solution for the following problem.
For example I have 5 timer what I start from 1 thread. These timers finish their work after few second (this is a retry mechanism). And I would like to wait to all of the timers finish their work.
So the question is that, Is there any good pattern which can handle this problem? Or do you now a good solution which is not a bool collection and if all of the elements are true then all of the timer finished :D
Thank you for your answer in advance!
This sounds like you really want to use Task instead of Timer.
Silly example:
async Task DoAsync()
{
var allTheWork = new [] { Work(), Work(), Work() };
await Task.WhenAll(allTheWork);
// Did all the sub-tasks return true?
if (allTheWork.All(i => i.Result))
{
}
}
async Task<bool> Work()
{
var retries = 3;
while (retries-- > 0)
{
if (success) return true;
await Task.Delay(2000); // This is the timer; you can find better retry patterns of course
}
return false;
}
There are multiple solutions to your problem.
I would suggest you take a look at Rx (Reactive Extensions) if you are familiar with linq since they use a very similar syntax. Rx allows you to do a lot of things with all sorts of events.
Another way is to use TPL (task parallel library) as follows:
var timer1 = Task.Delay(1000);
var timer2 = Task.Delay(2000);
var timer3 = Task.Delay(3000);
await Task.WhenAll(timer1, timer2, timer3);
Notice that you have to call this from an async context. If you are not familiar with async/await I recommend you take a look at it. If you don't want to / can't take a look at it you could simply do the following:
Task.WhenAll(timer1, timer2, timer3).GetAwaiter().GetResult();

What are the functional benefits of recursive scheduling in System.Reactive?

I'm current reading http://www.introtorx.com/ and I'm getting really interested in stripping Subject<T> out of my reactive code. I'm starting to understand how to encapsulate sequence generation so that I can reason better about a given sequence. I read a few SO questions and ended up reading about scheduling. Of particular interest is recursive scheduling, using the Schedule(this IScheduler scheduler, Action<TState,Action<TState>>)overloads - like this one.
The book is starting to show its age in a few areas, and the biggest i see is that it never compares its techniques to alternatives that may be achieved using the Task and async/await language features. I always end up feeling like I could write less code by ignoring the book advice and using the asynchronous toys, but the back of my mind nags me about being lazy and not learning the pattern properly.
With that, here is my question. If I wanted to schedule a sequence at an interval, support cancellation and perform work on a background thread, I might do this:
static void Main(string[] args)
{
var sequence = Observable.Create<object>(o =>
{
CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
DoWerk(o, cancellationTokenSource);
return cancellationTokenSource.Cancel;
});
sequence.Subscribe(p => Console.Write(p));
Console.ReadLine();
}
private static async void DoWerk(IObserver<object> o, CancellationTokenSource cancellationTokenSource)
{
string message = "hello world!";
for (int i = 0; i < message.Length; i++)
{
await Task.Delay(250, cancellationTokenSource.Token);
o.OnNext(message[i]);
if (cancellationTokenSource.IsCancellationRequested)
{
break;
}
}
o.OnCompleted();
}
Note the use of async void to create concurrency without explicitly borrowing a thread pool thread with Task.Run(). await Task.Delay() will, however, do just that but it will not lease the thread for long.
What are the limitations and pitfalls here? What are the reasons that you might prefer to use recursive scheduling?
I personally wouldn't use await Task.Delay(250, cancellationTokenSource.Token); as a way to slow down a loop. It's better than Thread.Sleep(250), but it's still code smell to me.
I would look at it that you should use a built-in operator in preference to a roll-your-own solution like this.
The operator you need is one of the most powerful, but often overlooked. Try Observable.Generate. He's how:
static void Main(string[] args)
{
IObservable<char> sequence = Observable.Create<char>(o =>
{
string message = "hello world!";
return
Observable
.Generate(
0,
n => n < message.Length,
n => n + 1,
n => message[n],
n => TimeSpan.FromMilliseconds(250.0))
.Subscribe(o);
});
using (sequence.Subscribe(p => Console.Write(p)))
{
Console.ReadLine();
}
}
This is self-cancelling (when you call .Dispose() on the subscription) and produces values every 250.0 milliseconds.
I've continued to use the Observable.Create operator to ensure that the message variable is encapsulated within the observable - otherwise it is possible for someone to change the value of message as the observable is working with it and thus break it.
As an alternative, that might not be as efficient with memory, but is self-encapsulating, try this:
IObservable<char> sequence =
Observable
.Generate(
"hello world!",
n => !String.IsNullOrEmpty(n),
n => n.Substring(1),
n => n[0],
n => TimeSpan.FromMilliseconds(250.0));
And, finally, there's nothing "recursive" about the scheduling in your question. What did you mean by that?
I finally figured out what you're looking at. I missed it in the question.
Here's an example using the recursive scheduling:
IObservable<char> sequence = Observable.Create<char>(o =>
{
string message = "hello world!";
return Scheduler.Default.Schedule<string>(message, TimeSpan.FromMilliseconds(250.0), (state, schedule) =>
{
if (!String.IsNullOrEmpty(state))
{
o.OnNext(state[0]);
schedule(state.Substring(1), TimeSpan.FromMilliseconds(250.0));
}
else
{
o.OnCompleted();
}
});
});

What Am I Missing About Reactive Extension Timers?

I have this:
watchers
.ToObservable() // needs to be observable
.SelectMany(watcher => // working on each watcher
Observable
// create a timer for the watcher
.Timer(watcher.StartTime, TimeSpan.FromHours(watcher.Interval))
.SelectMany(Observable.FromAsync(
async () => new { watcher, result = await CheckFolder(watcher.Path) })))
.Subscribe(x => Console.WriteLine(string.Format("Watcher: {0}\tResult: {1}\tTime: {2}", x.watcher.Name, x.result, DateTimeOffset.Now))); // tell everyone what happened.
Which is a nice little bit of code from this post that got me started down this road. The goal is to ping a web service (via the CheckFolder() method) every time the Timers publish, based on a given start time and interval.
The trouble is, every time I run the program it outputs a single message for the first Watcher, and then the program exits without error. It gets the first answer, and it's finished.
How do get it to wait for the other publications from all the timers?
I'm almost positive I'm not asking this question the right way, but hopefully a little feedback will help me refine my question.
Thanks.
This is likely because Subscribe is a non-blocking call. I.e. if you have;
static void Main(string[] args)
{
Observable.Timer(DateTimeOffset.Now, TimeSpan.FromSeconds(0.5))
.Subscribe(x => Console.WriteLine("Got " + x));
}
You'll probably find it prints nothing (or maybe "Got 0", depending on how your PC is feeling)
If you stop Main from exiting, by waiting for a key to be pressed, like this:
static void Main(string[] args)
{
Observable.Timer(DateTimeOffset.Now, TimeSpan.FromSeconds(0.5))
.Subscribe(x => Console.WriteLine("Got " + x));
Console.ReadKey();
}
Then it should keep printing out values until you press a key.
The thing to remember is that having an activating subscription, isn't enough to keep your programming running. If you're writing an application with some UI, then you'll usually have a message loop - which will your program alive until you close the window. But that isn't the case for console apps, once you get to the end of main, that's the end of your program.
So you need to find a way to avoid your app exiting before you're reading. Waiting for a specific key to be pressed is a common way to do it, so that may work for you. e.g.
static void Main(string[] args)
{
Observable.Timer(DateTimeOffset.Now, TimeSpan.FromSeconds(0.5))
.Subscribe(x => Console.WriteLine("Got " + x));
while (Console.ReadKey().Key != ConsoleKey.Q)
{
}
}

Track the (number of) observers in an Observable?

I have an observable which represents a stream of stock prices. If there are no observers on my observable sequence I'd like to be able to disconnect from the remote server that is supplying the stream of prices, but I don't want to do that until every observer has called Dispose(). Then in a similar fashion, when the first person calls Subscribe I'd like to reconnect to the remote server.
Is there a way to figure out how many observers have called subscribe on an observable? Or perhaps a way to know when observers are calling Subscribe or Dispose?
I would simply use RefCount / Publish. I always feel like if I'm implementing IObservable I'm working way too hard.
myColdObservable.Publish().RefCount();
This will make your observable stop pulsing after everyone has disconnected. Here's a sample:
var coldObservable = Observable
.Interval(TimeSpan.FromSeconds(1))
.ObserveOn(Scheduler.TaskPool)
.Select(_ => DoSomething());
var refCountObs = coldObservable.Publish().RefCount();
CompositeDisposable d = new CompositeDisposable();
d.Add(refCountObs.Subscribe(n => Console.WriteLine("First got: " + n)));
d.Add(refCountObs.Subscribe(n => Console.WriteLine("Second got: " + n)));
d.Add(refCountObs.Subscribe(n => Console.WriteLine("Third got: " + n)));
//Wait a bit for work to happen
System.Threading.Thread.Sleep(10000);
//Everyone unsubscribes
d.Dispose();
//Observe that DoSomething is not called.
System.Threading.Thread.Sleep(3000);
This does not cover the case where you actually want to know the number of subscribers, but I think this fits with your requirements of stopping work if there are no subscribers.
Bit of an old one but I came across this post as I had a problem where I needed to know the number of subscribers. Using Bart's suggestion I came up with this extension.
public static IObservable<T> CountSubscribers<T>(this IObservable<T> source, Action<int> countChanged)
{
int count = 0;
return Observable.Defer(() =>
{
count = Interlocked.Increment(ref count);
countChanged(count);
return source.Finally(() =>
{
count = Interlocked.Decrement(ref count);
countChanged(count);
});
});
}
In general, don't implement IObservable; typically there's already soemthing in Rx that can help you out, either directly or through composition. If you ever have to implement IObservable, use Observable.Create to do so, in order to get all the guaranteed required for the observer contract etc.
As for your problem - the suggestion of using Publish and RefCount is exactly the composition you're looking for. If you want to count yourself for some reason, use Observable.Defer to intercept subscriptions, possibly with Observable.Finally to intercept sequence terminations. Or, wrap the source with an Observable.Create, forward the observer to the wrapped sequence, and wrap the returned IDisposable with counting logic (using Disposable.Create).
Cheers,
-Bart (Rx team)
IObservable<T> is an interface that you can implement. In the Subscribe method of the interface you can keep track of observers by maintaining a list internally.
Following code snippet is from MSDN.
private List<IObserver<Location>> observers;
public IDisposable Subscribe(IObserver<Location> observer)
{
if (! observers.Contains(observer))
observers.Add(observer);
// ------- If observers.Count == 1 create connection. -------
return new Unsubscriber(observers, observer);
}
private class Unsubscriber : IDisposable
{
private List<IObserver<Location>>_observers;
private IObserver<Location> _observer;
public Unsubscriber(List<IObserver<Location>> observers, IObserver<Location> observer)
{
this._observers = observers;
this._observer = observer;
}
public void Dispose()
{
if (_observer != null && _observers.Contains(_observer))
_observers.Remove(_observer);
// ----------- if observers.Count == 0 close connection -----------
}
}

Categories