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.
Related
The application in question handles requests from clients which then requires a lot of calculation on the server side. This calculation is done piece-by-piece, so if the client is slow to read, this calculation should not progress (the calculation should respond to back-pressure).
The calculation is now represented as a Supplier<Buffer>, in which the get() call might take a long time and needs to be called multiple times until it responds with null (no more data). The get() should be called in a separate thread-pool (which is shared with other requests), and should only be called if the client is really able to accept the data.
My current code is:
ReadStream<Buffer> readStream = new MyComplicatedReadStream(supplier, executor)
.exceptionHandler(request::fail)
.endHandler(x -> request.response().end());
Pump.pump(readStream, request.response())).start();
I've made a custom implementation of ReadStream to do this, which sort-of works, but is long, clunky and has synchronization issues.
Instead of fixing that, I wonder if there is a idiomatic way in vert.x / rx to implement / instantiate a MyComplicatedReadStream. So, for a Supplier<Buffer> and an ExecutorService get a ReadStream<Buffer> which executes get() with the given executor and doesn't generate if it is paused.
I have near 0 experience with vert.x but I do have some experience with rxjava. So there might be a better way to do this but from rxjava perspective you can make use of generate method to create 'cold' flowables which only generate items on demand. I believe in this case when the stream is paused, no additional calls to supplier.get() will be made as there is no 'demand'
using kotlin syntax here but I think you can derive the java version easily.
Flowable.generate<Buffer> { emitter ->
val nextValue = supplier.get()
if (nextValue == null) {
emitter.onComplete()
} else {
emitter.onNext(nextValue)
}
}.subscribeOn(Schedulers.from(executor)) // this will make the above callback run in the given executor
Since it seems that the supplier is holding some state, you may in some cases want to generate a 'new supplier' for each consumer, in which case you can use the overload of the generate method that allows specifying another callback to get an instance of the state (supplier in your case). http://reactivex.io/RxJava/2.x/javadoc/io/reactivex/Flowable.html#generate-java.util.concurrent.Callable-io.reactivex.functions.BiConsumer-
Looks like then you can convert the flowable to a read stream:
ReadStream<Buffer> readStream = FlowableHelper.toReadStream(observable);
based on the docs here: https://vertx.tk/docs/vertx-rx/java2/#_read_stream_support
I have created a really simple example using RxJava 2 (everything I have developed was using RxJava 1) and I have found next behavior that I don't understand at all. I have next Observable with zip operation:
Observable.zip(getGame(gameId), getDetail(gameId), getReviews(gameId),
(game, detail, reviews) -> new GameInfo(game, detail, reviews))
.subscribeOn(Schedulers.newThread())
.subscribe(sendGameInfo(asyncResponse));
Each of the methods returns an instance of Observable. In theory, I would expect that each of the method (getGame, getDetail, ...) would be executed in parallel in a new Thread, but doing a sysout I noticed that all the time is the same Thread so they are not executed in parallel. I suppose that this is the expected behavior but if I would like to make in parallel is there a way to do it without having to define a runnable inside each of the observable?
Thank you very much.
Ok you need to subscribeOn every Observable
Observable.zip(getGame(gameId)
.subscribeOn(Schedulers.from(executor)),
getDetail(gameId)
.subscribeOn(Schedulers.from(executor)),
getReviews(gameId)
.subscribeOn(Schedulers.from(executor)),
(game, detail, reviews) -> new GameInfo(game, detail, reviews))
.subscribeOn(Schedulers.from(executor))
.subscribe(sendGameInfo(asyncResponse));
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.
I'm very new to RxJava, and I want to get content from 3 different webpages synchronously. How do I go about doing this?
You can use concat to make the calls happen in sequence:
Observable call1 = ...
Observable call2 = ...
Observable call3 = ...
Observable.concat(call1, call2, call3).subscribe(...);
You can use toBlocking to make the reception synchronous:
Observable.concat(call1, call2, call3).toBlocking().forEach(...);
I believe you want to achieve parallel execution of your observables, you can do this by using combineLastest operator. In short, you should create 3 observables and merge their results via combineLastest. In this case subscribe will be triggered once each observable emits something.
For further information, please see:
http://reactivex.io/documentation/operators/combinelatest.htm
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.