how does onNext is called in scala rx - scala

I'm trying to understand how observable works. Here is my code.
def make: Stream[Int] = {
Stream.cons(scala.util.Random.nextInt(10), {
println("Making ..")
Thread.sleep(1000)
make
})
}
val y = Observable.from(make)
y.foreach(a => println(a))
emit will produce new values every 1 second. I'm making an observable out of it. for each loop will go on forever printing newly produced values.
As I understand, a=>println(a) is a callback value which is called onNext(t) in rx observable.
What i'm trying to figure out is how that is glued to the producer so when new value is produced where does the onNext is called. I looked into rx code for a while and still cannot figure out.
Thanks.

It seems subscribe to the stream calls rx.Observable's
Subscription subscribe(Subscriber<? super T> subscriber)
This will call IterableProducer.request method
which will have this bit of code.
if (n == Long.MAX_VALUE && REQUESTED_UPDATER.compareAndSet(this, 0, Long.MAX_VALUE)) {
// fast-path without backpressure
while (it.hasNext()) {
if (o.isUnsubscribed()) {
return;
}
o.onNext(**it.next()**);
}
if (!o.isUnsubscribed()) {
o.onCompleted();
}
}
onNext is the observer code and input to it would be producers it.next. Thats how its glued.

Related

Why different behavior of Single when using just or fromCallable in startWith?

I'm starting a PublishSubject with testPublishSubject.startWith(createSingle().toObservable()).
If I subscribe to this observable, dispose and subscribe again, it will emit a different item depending on how I created the Single. If I create it with just, it emits the same item as the first time (item1), if I create it with fromCallable, it emits the updated item (item2). Why is the behavior different? Is there a way to use just and have it behave like fromCallable?
Edit: Ok, I think I know why it behaves differently. It's because it's not re-creating the Single. fromCallable works only because of the closure, which is executed again with the updated counter.
My updated question would be: Is there a way to have the subject re-create the Single? The reason I want this, is because the Single is fetching a value, which may have been updated, and I need to fetch it again.
var counter = 1
// With this, it works as expected
// fun createSingle(): Single<String> = Single.fromCallable {
// "item-${counter++}"
// }
// With this, the second subscription still shows "item-1
fun createSingle(): Single<String> = Single.just("item-${counter++}")
val testPublishSubject = PublishSubject.create<String>()
val observable = testPublishSubject.startWith(createSingle().toObservable().doOnNext {
log(">>> single on next: $it")
}).doOnNext {
log(">>> publish subject on next: $it")
}
log(">>> subscribing1")
val disposable1 = observable.subscribe {
log(">>> value subscription 1: $it")
}
log(">>> pushing random item")
testPublishSubject.onNext("random item")
log(">>> disposing subscription1")
disposable1.dispose()
log(">>> subscribing2")
val disposable2 = observable.subscribe {
log(">>> value subscription 2: $it")
}

Reactive extensions(Rx) Switch() produces new observable which is not subscribed to provided OnCompleted()

I have a problem with my Rx subscription using Switch statement.
_performSearchSubject
.AsObservable()
.Select(_ => PerformQuery())
.Switch()
.ObserveOn(_synchronizationContextService.SynchronizationContext)
.Subscribe(DataArrivedForPositions, PositionQueryError, PositionQueryCompleted)
.DisposeWith(this);
The flow is:
Some properties change and the performSearchSubject.OnNext is called
The PerformPositionQuery() is called, which returns a observer each time it is hit
The service which responds through this observer calls OnNext twice and OnCompleted once when the data receive is done
Method DataArrivedForPositions is called twice as expected
Method PositionQueryCompleted is never called, though observer.OnCompleted() is called inside my data service.
Code for dataService is:
protected override void Request(Request request, IObserver<Response> observer)
{
query.Arrive += p => QueryReceive(request.RequestId, p, observer, query);
query.Error += (type, s, message) => QueryError(observer, message);
query.NoMoreData += id => QueryCompleted(observer);
query.Execute(request);
}
private void QueryError(IObserver<PositionSheetResponse> observer, string message)
{
observer.OnError(new Exception(message));
}
private void QueryCompleted(IObserver<PositionSheetResponse> observer)
{
observer.OnCompleted();
}
private void QueryReceive(Guid requestId, Qry0079Receive receiveData, IObserver<PositionSheetResponse> observer, IQry0079PositionSheet query)
{
observer.OnNext(ConvertToResponse(requestId, receiveData));
}
Switch result will only Complete when your outer observable (_performSearchSubject) completes. I assume in your case this one never does (it's probably bound to a user action performing the search).
What's unclear is when you expect PositionQueryCompleted to be called. If It's after each and every successful query is processed, then your stream needs to be modified, because Switch lost you the information that the query stream completed, but it also lacks information about the UI (wrong scheduler even) to say whether its data was actually processed.
There may be other ways to achieve it, but basically you want your query stream complete to survive through Switch (which currently ignore this event). For instance you can transform your query stream to have n+1 events, with one extra for the complete:
_performSearchSubject
.AsObservable()
.Select(_ =>
PerformQuery()
.Select(Data => new { Data, Complete = false})
.Concat(Observable.Return(new { Data = (string)null, Complete = true })))
You can safely apply .Switch().ObserveOn(_synchronizationContextService.SynchronizationContext) on it, but then you need to modify your subscription:
.Subscribe(data => {
if (data.Complete) DataArrivedForPositions(data.Data);
else PositionQueryCompleted()
}, PositionQueryError)

Rxjava User-Retry observable with .cache operator?

i've an observable that I create with the following code.
Observable.create(new Observable.OnSubscribe<ReturnType>() {
#Override
public void call(Subscriber<? super ReturnType> subscriber) {
try {
if (!subscriber.isUnsubscribed()) {
subscriber.onNext(performRequest());
}
subscriber.onCompleted();
} catch (Exception e) {
subscriber.onError(e);
}
}
});
performRequest() will perform a long running task as you might expect.
Now, since i might be launching the same Observable twice or more in a very short amount of time, I decided to write such transformer:
protected Observable.Transformer<ReturnType, ReturnType> attachToRunningTaskIfAvailable() {
return origObservable -> {
synchronized (mapOfRunningTasks) {
// If not in maps
if ( ! mapOfRunningTasks.containsKey(getCacheKey()) ) {
Timber.d("Cache miss for %s", getCacheKey());
mapOfRunningTasks.put(
getCacheKey(),
origObservable
.doOnTerminate(() -> {
Timber.d("Removed from tasks %s", getCacheKey());
synchronized (mapOfRunningTasks) {
mapOfRunningTasks.remove(getCacheKey());
}
})
.cache()
);
} else {
Timber.d("Cache Hit for %s", getCacheKey());
}
return mapOfRunningTasks.get(getCacheKey());
}
};
}
Which basically puts the original .cache observable in a HashMap<String, Observable>.
This basically disallows multiple requests with the same getCacheKey() (Example login) to call performRequest() in parallel. Instead, if a second login request arrives while another is in progress, the second request observable gets "discarded" and the already-running will be used instead. => All the calls to onNext are going to be cached and sent to both subscribers actually hitting my backend only once.
Now, suppouse this code:
// Observable loginTask
public void doLogin(Observable<UserInfo> loginTask) {
loginTask.subscribe(
(userInfo) -> {},
(throwable) -> {
if (userWantsToRetry()) {
doLogin(loinTask);
}
}
);
}
Where loginTask was composed with the previous transformer. Well, when an error occurs (might be connectivity) and the userWantsToRetry() then i'll basically re-call the method with the same observable. Unfortunately that has been cached and I'll receive the same error without hitting performRequest() again since the sequence gets replayed.
Is there a way I could have both the "same requests grouping" behavior that the transformer provides me AND the retry button?
Your question has a lot going on and it's hard to put it into direct terms. I can make a couple recommendations though. Firstly your Observable.create can be simplified by using an Observable.defer(Func0<Observable<T>>). This will run the func every time a new subscriber is subscribed and catch and channel any exceptions to the subscriber's onError.
Observable.defer(() -> {
return Observable.just(performRequest());
});
Next, you can use observable.repeatWhen(Func1<Observable<Void>, Observable<?>>) to decide when you want to retry. Repeat operators will re-subscribe to the observable after an onComplete event. This particular overload will send an event to a subject when an onComplete event is received. The function you provide will receive this subject. Your function should call something like takeWhile(predicate) and onComplete when you do not want to retry again.
Observable.just(1,2,3).flatMap((Integer num) -> {
final AtomicInteger tryCount = new AtomicInteger(0);
return Observable.just(num)
.repeatWhen((Observable<? extends Void> notifications) ->
notifications.takeWhile((x) -> num == 2 && tryCount.incrementAndGet() != 3));
})
.subscribe(System.out::println);
Output:
1
2
2
2
3
The above example shows that retries are aloud when the event is not 2 and up to a max of 22 retries. If you switch to a repeatWhen then the flatMap would contain your decision as to use a cached observable or the realWork observable. Hope this helps!

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")
}
)
}

How to Merge or skip duplicate messages in a Scala Actor?

Let's say you have a gui component and 10 threads all tell it to repaint at sufficiently the same time as they all arrive before a single paint operation takes place. Instead of naively wasting resources repainting 10 times, just merge/ignore all but the last one and repaint once (or more likely, twice--once for the first, and once for the last). My understanding is that the Swing repaint manager does this.
Is there a way to accomplish this same type of behavior in a Scala Actor? Is there a way to look at the queue and merge messages, or ignore all but the last of a certain type or something?
Something like this?:
act =
loop {
react {
case Repaint(a, b) => if (lastRepaint + minInterval < System.currentTimeMillis) {
lastRepaint = System.currentTimeMillis
repaint(a, b)
}
}
If you want to repaint whenever the actor's thread gets a chance, but no more, then:
(UPDATE: repainting using the last message arguments)
act =
loop {
react {
case r#Repaint(_, _) =>
var lastMsg = r
def findLast: Unit = {
reactWithin(0) {
case r#Repaint(_, _) =>
lastMsg = r
case TIMEOUT => repaint(lastMsg.a, lastMsg.b)
}
}
findLast
}
}