How does task cancellation work in RxJava? - java

I'm unclear on how to implement task cancellation in RXJava.
I'm interested in porting an existing API built using Guava's ListenableFuture. My use case is as follows:
I have an single operation that's composed of a sequence of futures joined by Futures.transform()
Multiple subscribers observe the operation's final future.
Each observer can cancel the final future, and all observers witness the cancellation event.
Cancellation of the final future results in the cancellation of its dependencies, e.g. in sequence 1->2->3, cancellation of 3 is propagated to 2, and so on.
There's very little info in the RxJava wiki about this; the only references I can find to cancellation mention Subscription as an equivalent to .NET's Disposable, but as far as I can see, Subscription only offers the ability to unsubscribe from subsequent values in the sequence.
I'm unclear on how to implement "any subscriber can cancel" semantics through this API. Am I thinking about this in the wrong way?
Any input would be appreciated.

It's important to learn about Cold vs Hot Observables. If your Observables are cold, then their operations will not execute if you have no subscribers. Hence to "cancel", just make sure all Observers unsubscribe from the source Observable.
However, if only one Observer of the source unsubscribes, and there are other Observers still subscribed to the source, this will not incur a "cancelling". In that case you can use (but it's not the only solution) ConnectableObservables. Also see this link about Rx.NET.
A practical way of using ConnectableObservables is to simply call .publish().refCount() on any cold Observable. What that does is create one single "proxy" Observer which relays the events from the source to the actual Observers. The proxy Observer unsubscribes when the last actual Observer unsubscribes.
To manually control a ConnectableObservable, call just coldSource.publish() and you will get an instance of ConnectableObservable. Then you can call .connect() which will return you the Subscription of the "proxy" Observer. To manually "cancel" the source, you just unsubscribe the Subscription of the proxy Observer.
For your specific problem, you can also use the .takeUntil() operator.
Suppose your "final future" is ported as finalStream in RxJava, and suppose that "cancel events" are Observables cancelStream1, cancelStream2, etc, then it becomes fairly simple to "cancel" operations resulting from finalStream:
Observable<FooBar> finalAndCancelableStream = finalStream
.takeUntil( Observable.merge(cancelStream1, cancelStream2) );
In diagrams, this is how takeUntil works, and this is how merge works.
In plain english, you can read it as "finalAndCancelableStream is the finalStream until either cancelStream1 or cancelStream2 emit an event".

Related

Reactor Multiplexing: Dispatch event to just exactly one subscriber

I am playing a bit with Reactor right now. While trying to build a small demo game (just to get accustomed to the framework), I need the ability to have multiple "entities" subscribed to a publisher. But I also need each published event to reach exactly one subscriber. For now, they all always get it. I know that I could build some "latch" into this event so that all but one subscriber discard it.
But I think in the sea of features, there might be an operator or something that already does exactly this...
Multiple subscribers to a single publisher. Each subscriber would need to apply a different filter too though.
Each event from the publisher going only to a single subscriber in no particular order... (The filter does not guarantee uniqueness, there could be multiple subscribers using the same filter).
Randomness is cool but not required (since the subscriber will unsubscribe upon receiving this event). You might have guessed that this will be the kill signal for the entity ;).
Thanks!
Looks like UnicastProcessor does the trick.

Implementing an event bus with priorized subscribers and concurrent modification

I have several parts of my application, that need to react to events triggered from somewhere else, so the first thing I thought about would be an event bus. These are the requirements I see:
The subscriber method should be typesafe
Implementing an interface (like Subscriber<T>) is not a problem
A subscriber should also receive any events of subtypes to the class it's registered to
Subscribers should be able to be registered with a priority (a simple int) or a default priority hardcoded somewhere in the code. When posting an event, the subscribers will be called in order. The events are mutable and some of their fields will change between subscribers
Each thread will have its own event bus and I will manually register all subscribers, so there's no need for static access
While receiving an event, it should be possible for a subscriber to unsubscribe without raising a ConcurrentModificationException
Bonus requirements I might need down the line:
Register new subscribers while handling events
Send events while receiving one. Those will be processed synchronously before proceeding with the current task
The option to "pool" events that currently have no subscriber and manually process them later (maybe by passing a Consumer).
Guava Eventbus probably does most of those things except for the priority. I can create a simple prioritized subscriber queue by using a TreeSet, but I'm not sure how to integrate it into Guava and I don't know if I want to depend on the whole library just for the bus.
Also, I might need a CopyOnWriteArrayList for the concurrent stuff (adding/removing while iterating), but I don't know about the performance implications. On that note, there probably won't be more than 10-15 subscribers at a time.
Normal events are not designed to be mutable. You should stick with immutable data. Also subscribers are not intendet to be called within a certain order or to interact with another.
For your usecase you could build different event busses for each priority. A subscriber could handover a copy of the modified event to the next priority bus.

What does share operator do in RxJava? When should I use it?

I know that share() is a replacement of publish().refCount().
Then from the RxJava wiki:
Observable.publish( ) — represents an Observable as a Connectable Observable
ConnectableObservable.refCount( ) — makes a Connectable Observable behave like an ordinary Observable
This make me confused. If after publish().refCount(), it just behave like an ordinary Observable, why should I use it, how does this api make sense?
You're right - Observable.share is just a shortcut for publish().refCount(). I think that description you have quoted above is not entirely clear as ConnectedObservable.refCount does a little bit more :)
If you transform your Observable to ConnectableObservable - it will not emit items (even if something is subscribed) unless explicitly called ConnectableObservable.connect - it basically defers execution of subscribe method and prevents from executing it multiple times for every subscriber. This technique is often used to make sure that all subscribers are subscribed before observable starts emitting items (in other words - after everyone has subscribed - connect() method is called).
If you have more than one subscriber (what often happens), you have to handle their subscriptions and unsubscriptions and this is where things are getting tricky. This is why refCount() was introduced. This operator returns new Observable, keeps track of how many subscribers are subscribed to it and stays connected as long as there is at least one subscription. It will also automatically connect when the first subscriber appears.
PS. I'm learning how to use RxJava, if I am wrong - please point it out!

Query on RxJava observeOn scheduler thread

I have to write into a file based on the incoming requests. As multiple requests may come simultaneously, I don't want multiple threads trying to overwrite the file content together, which may lead into losing some data.
Hence, I tried collecting all the requests' data using a instance variable of PublishSubject. I subscribed publishSubject during init and this subscription will remain throughout the life-cycle of application. Also I'm observing the same instance on a separate thread (provided by Vertx event loop) which invokes the method responsible for writing the file.
private PublishSubject<FileData> publishSubject = PublishSubject.create();
private void init() {
publishSubject.observeOn(RxHelper.blockingScheduler(vertx)).subscribe(fileData -> writeData(fileData));
}
Later during request handling, I call onNext as below:
handleRequest() {
//do some task
publishSubject.onNext(fileData);
}
I understand that, when I call onNext, the data will be queued up, to be written into the file by the specific thread which was assigned by observeOn operator. However, what I'm trying to understand is
whether this thread gets blocked in WAITING state for only this
task? Or,
will it be used for other activities also when no file
writing happens?
I don't want to end up with one thread from the vertx event loop wasted in waiting state for going with this approach. Also, please suggest any better approach, if available.
Thanks in advance.
Actually RxJava will do it for you, by definition onNext() emissions will act in serial fashion:
Observables must issue notifications to observers serially (not in parallel). They may issue these notifications from different threads, but there must be a formal happens-before relationship between the notifications. (Observable Contract)
So as long as you will run blocking calls inside the onNext() at the subscriber (and will not fork work to a different thread manually) you will be fine, and no parallel writes will be happen.
Actually, you're worries should come from the opposite direction - Backpressure.
You should choose your backpressure strategy here, as if the requests will come faster then you will process them (writing to file) you might overflow the buffer and get into troubles. (consider using Flowable and choose you're backpressure strategy according to your needs.
Regarding your questions, that depends on the Scheduler, you're using RxHelper.blockingScheduler(vertx) which seems like your custom code, so I can't tell, if the scheduler is using shared thread in work queue fashion then it will not stay idle.
Anyhow, Rx will not determine this for you, the scheduler responsibility is to assign the work to some thread according to its logic.

How long does an event live in the eventbus?

I would like to #Subscribe a method in a Runnable that is created by a ScheduledFuture, so that I can signal it from another thread whether to run. Because a ScheduledFuture creates the object at some future time, there is no scope for the #Subscribe listener to pick up my event. So, I'm wondering how long an event sits in the bus, waiting to picked up by a listener? Is the actual pub-sub synchronous wrt sending/receiving events or will they sit in a queue for some duration before timing out?
Thanks.
Guava's EventBus does not provide sticky events. Additionally, due to the design of EventBus, it's not as straightforward as it could be to extend it to implement such a sticky design, as a lot of the internals are package-private (e.g. the logic to discover which methods on a registered object are annotated with Subscribe and mapping them to the proper event type).
I do think there are some other libraries out there which do provide this, like GreenRobot's event bus (https://github.com/greenrobot/EventBus), but without introducing a new library you'll have to build it more or less from scratch.
An alternative that I've used is RxJava's Observables with a replay(1) operator, so that subscribing to the observable will always immediately invoke the subscription callback with the last item, but it's not a drop-in replacement.

Categories