RxSwift how to have two Observables be bound for completion together? - reactive-programming

I have two Observables and I want them both to terminate with completion event when either of them is completed. They both branch from the same sequence, but have different termination condition:
.filter.take(1)
.distinctUntilChanged.take(2)
How can I have two Observables complete together when either one completes?

I think you need to manage subscriptions manually, here is an example:
var disposable1: Disposable?
var disposable2: Disposable?
disposable1 = observable.filter().take(1).subscribe(onDisposed: {
disposable2?.dispose()
})
disposable2 = observable.distinctUntilChanged().take(2).subscribe(onDisposed: {
disposable1?.dispose()
})

Related

SwiftUI Combine synchronously execute codes

I call an API and perform some actions based on the response.
let test = apiPublisher
.subscribe(...)
.receive(...)
.share()
test
.sink {
//do task1
}.store(...)
test
.sink {
//do task2
}.store(...)
test
.sink {
//do task3
}.store(...)
Now how can I execute the task1, task2, task3 one after another. I know I can have all the code in one sink block. For code readability I'm using the share() operator.
Code put in sinks need to be independent. If you want them to depend on each other (one should not start until the other finishes) then you can't put them in sinks.
You will have to put each task in its own Publisher. That way the system will know when each is finished and you can concat them.
test.task1
.append(test.task2)
.append(test.task3)
.sink { }
.store(...)
I'm assuming that each task needs something from test in order to perform its side effect. Also each task needs to emit a Void event before completing.

Is there a Rx.Net Operator that tells the number of subscribed observers?

I am trying to debug if I am correctly disposing the observers to a long running services (services exposing IObservable). And I am wondering if there an operator or something that we can create to log the number of active observers, say something like.
public class NewsService
{
IObservable<Article> GetArticles();
}
NewsService.Instance
.GetArticles()
.DoCount(x=> Trace.Writeline("The current count is {x}"))
.Subscribe();
There is a solution proposed here, which works on the Subject. What if we don't have access to the Subject and a library is exposing IObservable.
Generally speaking, the concept of subscriber count for an arbitrary observable sequence is not defined.
For cold observables such as Observable.Interval, every time you subscribe to the observable, a new pipeline instance is created, which - from its point of view sees only a single observer at a time.
We can, nonetheless, warm up a cold observable, and watch subscriptions come and go.
public static IObservable<T> RefCount<T>(this IObservable<T> source, Action<int> onChange)
{
var subscribers = 0;
var shared = source.Publish().RefCount();
void callback(int count) => onChange(Interlocked.Add(ref subscribers, count));
return Observable.Create<T>(observer =>
{
callback(+1);
var subscription = shared.Subscribe(observer);
var dispose = Disposable.Create(() => callback(-1));
return new CompositeDisposable(subscription, dispose);
});
}
Demo
var values =
Observable
.Interval(TimeSpan.FromSeconds(0.1))
.RefCount(count => Console.WriteLine($"Subscribers: {count}"));
values.Take(5).Subscribe();
values.Take(10).Subscribe();
values.Take(15).Subscribe();
Output
Subscribers: 1
Subscribers: 2
Subscribers: 3
Subscribers: 2
Subscribers: 1
Subscribers: 0
Now, this works because we have a shared view of the parent observable.
So try to make all subscriptions point to the same instance.
_articles = GetArticles().RefCount(count => Console.WriteLine($"Subscribers: {count}")));
...
_articles.Subscribe();

How do I sequentially loop an observable in RxSwift?

I am trying to create a stream that polls a network service. At the moment it queries the service then completes after a short delay. I'd like the onward stream to restart rather than completing thereby polling the service forever.
You could do something like ...
myPollingStream.repeat()
But repeat in RxSwift is actually repeatElement and so actually generates a stream of observables. You could possibly concatMap these into a flattened serial sequence but RxSwift does not have the concatMap operator.
So how do I loop an observable in RxSwift?
I'd like the requests to be sequential, not concurrent so flatMap is not an option since it merges streams leading to overlapping requests. I'm looking for something similar to how retry() works but restarting onComplete not onError
Observable.repeatElement(myPollingStream, scheduler: MainScheduler.instance).concat()
repeatElement(_:scheduler:) will create an infinite stream of polling queries.
contat() will then make sure each polling query is completed before subscribing to the next.
Attention
While the above works in theory, without a backpressure implemetation, repeatElements(_:scheduler:) will emit events until you eventually run out of memory. This makes this solution not viable as of RxSwift 3.0. More details can be found in this issue on RxSwift repository.
Option 1: Recursive function
Your myPollingStream:
func myPollingStream() -> Observable<Result> {
return Observable<String>.create { observer in
// your network code here
return Disposables.create()
}
}
Then you create a a recursive function:
func callMyPollingStream() {
myPollingStream()
.subscribe(onNext: { result in
callMyPollingStream() // when onNext or onCompleted, call it again
})
.addDisposableTo(db)
}
Option 2: Use interval
let _ = Observable<Int>
.interval(5, scheduler: MainScheduler.instance)
.subscribe(onNext: { _ in
let _ = myPollingStream().subscribe()
})
.addDisposableTo(db)
With this option, myPollingStream() function will be called every 5 seconds.

Why does head not cancel subscription

Let's say you have the following Observable in rxjava-scala-0.18.4
#volatile var dorun = true
var subscriber: Subscriber[String] = null
val myObs = Observable { obs: Subscriber[String] =>
subscriber = obs
Subscription { println("unsubscribed"); dorun = false }
}
val sub = myObs.head.subscribe(println(_))
assertTrue(dorun)
subscriber.onNext("hello")
Thread.sleep(500)
assertFalse(dorun)
subscriber.onNext("world")
Thread.sleep(500)
assertFalse(dorun)
The second assertion fails, which means that head does not unsubscriby. Is my understanding of Observables wrong or should head unsubscribe after the first element got emitted?
Take a look at your subscribe() method: you loop until run is set to false, but the only way for that to happen would be to close the subscription. The problem is that nobody has the subscription yet: the loop keeps you from returning. The head operator can't terminate the underlying subscription after the first item is delivered because it hasn't finished subscribing yet. Thus, you just keep looping forever.
One solution would be to move your loop into an action scheduled on Schedulers.trampoline(). Then the events would be delivered some time after returning from subscribe().
Additionally, in your subscribe() method, it seems you need to add the new subscription object to the Subscriber that gets passed in, like so:
val myObs = Observable {
obs: rx.lang.scala.Subscriber[String] =>
...
obs.add(
Subscription {
dorun = false
println("unsubscribed")
}
)
}

rx reactive extension: how to have each subscriber get a different value (the next one) from an observable?

Using reactive extension, it is easy to subscribe 2 times to the same observable.
When a new value is available in the observable, both subscribers are called with this same value.
Is there a way to have each subscriber get a different value (the next one) from this observable ?
Ex of what i'm after:
source sequence: [1,2,3,4,5,...] (infinite)
The source is constantly adding new items at an unknown rate.
I'm trying to execute a lenghty async action for each item using N subscribers.
1st subscriber: 1,2,4,...
2nd subscriber: 3,5,...
...
or
1st subscriber: 1,3,...
2nd subscriber: 2,4,5,...
...
or
1st subscriber: 1,3,5,...
2nd subscriber: 2,4,6,...
I would agree with Asti.
You could use Rx to populate a Queue (Blocking Collection) and then have competing consumers read from the queue. This way if one process was for some reason faster it could pick up the next item potentially before the other consumer if it was still busy.
However, if you want to do it, against good advice :), then you could just use the Select operator that will provide you with the index of each element. You can then pass that down to your subscribers and they can fiter on a modulus. (Yuck! Leaky abstractions, magic numbers, potentially blocking, potentiall side effects to the source sequence etc)
var source = Obserservable.Interval(1.Seconds())
.Select((i,element)=>{new Index=i, Element=element});
var subscription1 = source.Where(x=>x.Index%2==0).Subscribe(x=>DoWithThing1(x.Element));
var subscription2 = source.Where(x=>x.Index%2==1).Subscribe(x=>DoWithThing2(x.Element));
Also remember that the work done on the OnNext handler if it is blocking will still block the scheduler that it is on. This could affect the speed of your source/producer. Another reason why Asti's answer is a better option.
Ask if that is not clear :-)
How about:
IObservable<TRet> SomeLengthyOperation(T input)
{
return Observable.Defer(() => Observable.Start(() => {
return someCalculatedValueThatTookALongTime;
}, Scheduler.TaskPoolScheduler));
}
someObservableSource
.SelectMany(x => SomeLengthyOperation(input))
.Subscribe(x => Console.WriteLine("The result was {0}", x);
You can even limit the number of concurrent operations:
someObservableSource
.Select(x => SomeLengthyOperation(input))
.Merge(4 /* at a time */)
.Subscribe(x => Console.WriteLine("The result was {0}", x);
It's important for the Merge(4) to work, that the Observable returned by SomeLengthyOperation be a Cold Observable, which is what the Defer does here - it makes the Observable.Start not happen until someone Subscribes.