RxJava: restart from the beginning on each subscription - java

Imagine I have some time consuming task which I want to run only occasionally.
I want to wrap it into an observable and pass it to some component.
That component will subscribe to this observable whenever it wants to retrieve the data, and unsubscribe after it receives it.
I.e. I want an observable which upon subscription would invoke some expensive API call, and this API call can return a different data each time it is called - and then this observable would shut down until next subscription is made.
Is this possible to achieve?
I have seen 'replay()' and 'cache()' operators, but they won't work because from what I understood, they will cache once and then replay cached values which fails my case of changing data.
Also there is 'observable.publish()' but it seems that this will make a hot observable which will stay connected to the source observable all the time...

As I understand your question, you need a cold observable.
Observable<Integer> obs = Observable.from(1, 2, 3, 4);
obs.subscribe(); // will iter over values
obs.subscribe(); // will iter AGAIN over values
So, if your observable is your api call, and it's a cold observable, just subscribe twice on it to perform two api calls.

Related

Is it OK to share observables between multiple clients using SSE?

I have a service (ServiceA) with an endpoint to which client can subscribe and after subscription, this service produces data continuously using server sent events.
If this is important, I am using Project Reactor with Java.
It may be important, so I'll explain what this endpoint does. Every 15 seconds it fetches data from another service (ServiceB), checks if there were some changes with data that it fetched 15 seconds ago and if there were, it prouces a new event with this data, if there were no changes, it does not send anything (so the payload to the client is as small as possible).
Now, this application can have multiple clients connected at once and they all ask for the same data - it is not filtered by the user etc.
Is it sensible that this observable producing the output is shared between multiple clients?
Of course it would save us a lot of unnecessary calls to the ServiceB, but I wonder if there are any counterindications to this approach - it is the first time I am writing reactive program on the backend (coming from the RxJS) and I don't know if this would cause any concurrency problems or any other sort of problems.
The other benefit I can see is that a new client connecting would immediately be served the last received data from the ServiceB (it usually takes about 4s per call to retrieve this data).
I also wonder if it would be possible that this observable is calling the ServiceB only if there are some subscribers - i.e. until there is at least one subscriber, call the service, if there are no subscribers stop calling it, when a new subscriber subscribes call it again but first fetch the client the last fetched data (no matter how old or stale it may be).
your SSE source can perfectly be shared using the following pattern:
source.publish().refCount();
Note that you need to store the return value of that call and return that same instance to subsequent callers in order for the sharing to occur.
Once all subscribers unsubscribe, refCount will also cancel its subscription to the original source. After that the first subscriber to come in will trigger a new subscription to the source, which you should craft so that it fetches the latest data and re-initializes a polling cycle every 15s.

RXJava 2 Polling with multiple subscribers

i would like to start replacing/using RXJava2 for polling instead of Observer and Listeners. Now there is just one Problem. Ive one Polling Observable which should only be started if at least one Subscriber is connected. If multiple subscribers are connected the Interval should be the same. means: One observable repeat the Polling process all n Seconds. If the observable has 1..* subscribers it should keep polling n Seconds and notify all subscribers with the result.
This is how i have done this with Listeners and/or with my RXJava Solution.
My first try is creating a Singleton Class which creates only one PublishSubject. If someone is subscribed it will get the data in onNext(). Now my Polling Observer is started somewhere and push the Data to the Subject. This doesnt work as excepted since it's
bad pattern design
doesnt start ONLY if a subscriber is connected and stops if no subscribers are available
doesnt share the data successfull and requires two classes (for subject and repeating observable)
public class SingleTonClass {
private PublishSubject<List<Data>> subject = PublishSubject.create();
public PublishSubject getSubject() {
return this.subject;
}
public void setData(List<Data> data) {
subject.onNext(data);
}
}
I would lovely avoid Listener/Interfaces to share the informations around and let rxjava2 do its job.
After a research i figured out that there is refcount() and share() but im not sure if this is the proper way solving this. In my case it's for a REST-Service which polls the server if at least one subscriber is connected elsehow it should stop polling since it doesnt make sense getting the data in this case.
I tried to solve it onec but it doesnt work as excepted:
Polling using RXJava2 / RXAndroid 2 and Retrofit
I would do it like this:
Observable<Data> dataSource = Observable.interval(INTERVAL, TIME_UNIT)
.observeOn(Schedulers.io()) // make REST requests on IO threads
.map(n -> {
return requestData();
})
.replay(1);
replay() operator includes share(), which in turn includes publish() and refCount() functionalities. This makes your observable hot, i.e. all subscribers share single subscription. It automatically subscribes (starts new interval sequence) with the first subscriber, and unsubscribes (stops interval) when last subscriber is gone.
replay(1) also caches last emitted value, i.e. new subscribers do not have to wait for new data to arrive.

How can I explicitly signal completion of a Flowable in RxJava?

I'm trying to create a Flowable which is wrapping an Iterable. I push elements to my Iterable periodically but it seems that the completion event is implicit. I don't know how to signal that processing is complete. For example in my code:
// note that this code is written in Kotlin
val iterable = LinkedBlockingQueue<Int>()
iterable.addAll(listOf(1, 2, 3))
val flowable = Flowable.fromIterable(iterable)
.subscribeOn(Schedulers.computation())
.observeOn(Schedulers.computation())
flowable.subscribe(::println, {it.printStackTrace()}, {println("completed")})
iterable.add(4)
Thread.sleep(1000)
iterable.add(5)
Thread.sleep(1000)
This prints:
1
2
3
4
completed
I checked the source of the Flowable interface but it seems that I can't signal that a Flowable is complete explicitly. How can I do so? In my program I publish events which have some delay between them and I would like to be explicit when to complete the event flow.
Clarification:
I have a long running process which emits events. I gather them in a queue and I expose a method which returns a Flowable which wraps around my queue. The problem is that there might be already elements in the queue when I create the Flowable. I will process the events only once and I know when the flow of events stops so I know when I need to complete the Flowable.
Using .fromIterable is the wrong way to create a Flowable for your use case.
Im not actually clear on what that use case is, but you probably want to use Flowable.create() or a PublishSubject
val flowable = Flowable.create<Int>( {
it.onNext(1)
it.onNext(2)
it.onComplete()
}, BackpressureStrategy.MISSING)
val publishSubject = PublishSubject.create<Int>()
val flowableFromSubject = publishSubject.toFlowable(BackpressureStrategy.MISSING)
//This data will be dropepd unless something is subscribed to the flowable.
publishSubject.onNext(1)
publishSubject.onNext(2)
publishSubject.onComplete()
Of course how you deal with back-pressure will depend on the nature of the source of data.
Like suggested by akarnokd, ReplayProcessor do exactly what you want. Replace iterable.add(item) with processor.onNext(item), and call processor.onComplete() when you are done.

Subscribing to an observable modified using .share() after it has disposed resources already

Here is the problem,
I have a network request which downloads some information. However, it is essential that this request is called only once during some period of time ( you will get the idea later on ) and all subscribers get the same result. My first thought was to use the share() operator, so it would multicast the result while keeping a single request source. But I am not sure what is going to happen if I try to subscribe to it again after the share operator already disposed the resources due to refCount dropping to 0.
The thing I am trying to accomplish here is that every request that I make, is dependent on the current state of information stored and those requests update this information. Once I make the first request, I need to keep a reference to it and inform every subscriber that subscribes until the time of request completion. After the request is finished, all subscribers gets their notification and unsubscribes... However, if there is a new subscription after the disposal I need it to repeat the request, thus resubscribing to the original source observable that was modified using share
Is something like this possible with simple share operator, or do I need to create a subject and control the emissions manually ?
There is a nice library RxReplayingShare, which I think makes exactly, what you are trying to achieve.
It passes the same result to all Subscriber's, when at least one is subscribed. When there are no subscribers anymore, the Observable completes. When subscribing again, the original Observable is called.
The RxMarble shows it better than the description.

How to debounce a retrofit reactive request in java?

I'm working on an android project that makes requests through retrofit using Rx-Java observable and subscribe.
However, in some interactions this request can be called multiple times and I would like to only execute the last one in a predefined window of time (debounce).
I tried to apply the debounce operator directly to the observable, but it will not work because the code below is executed every time some interaction occurs:
mApi.getOnlineUsers()
.debounce(1, TimeUnit.SECONDS)
.subscribe(...)
I guess it should be created only one observable and every interaction it should "append" the execution to the same observable. But I am kind of new on Rx Java and don't know exactly what to do.
Thanks!
Suppose you want to start an execution according to some trigger event.
Observable<Event> trigger = ... // e.g. button clicks
You can transform the trigger events to calls to your API like this:
trigger
.debounce(1, TimeUnit.SECONDS)
.flatMap(event -> mApi.getOnlineUsers())
.subscribe(users -> showThemSomewhere(users));
Also, notice that the debounce operator will take the last occurrence within the time frame, but throttlefirst will take the first. You may want to use one or the other depending on your use case.

Categories

Resources