I want to use synchronized block for source of flatMap. But I need to use this construct for processing (method processItem), not only when inner source is created.
This Observable is called each 5 minutes (for example Observable.interval)
Observable.fromIterable(getSourceData())
.flatMapCompletable(item -> {
synchronized(LockManager.getInstance().getLockObject(item.id)){
return processItem(item)
.subscribeOn(Schedulers.io());
}
})
My processsItem method looks like:
public Completable processItem(Item item){
return mApiSource.getItemById(item.id)
.flatMap(item ->
mItemRepository.replace(item)
)
.toCompletable();
}
Both inner methods return Single.
It is part of method for periodic updates from server. I need to serialize processItem method call (periodic synchronization of item from server) with methods for modifiction of Item (update, delete) which are called from other classes of project (synchronization for item with ).
Main problem is that periodic update can rewrite newly updated item.
Actually I use this solution:
Chain for updating new item:
public Completable updateItem(Item item){
return Completable.fromAction(() -> {
synchronized(LockManager.getInstance().getLockObject(item.id)){
mApiSource.update(item)
.flatMap(item ->
mItemRepository.replace(item)
)
.toCompletable()
.blockingAwait();
}
})
.subscribeOn(Schedulers.io())
}
Chain for periodic update:
Observable.fromIterable(getSourceData())
.flatMapCompletable(item -> {
Completable.fromAction(() ->{
synchronized(LockManager.getInstance().getLockObject(item.id)){
processItem(item).blockingAwait();
}
})
.subscribeOn(Schedulers.io())
});
I know that is not clear RxJava solution.
Do you know better solution for this problem?
Related
I am trying to use project reactor mergeWith operator in order to achieve a if/elseif/else branching logic as described here: RxJS, where is the If-Else Operator.
The provided samples are written in RxJS but the underlying idea remains the same.
Basically the idea is to use the filter operator on 3 monos/publishers (therefore with 3 different predicates) and merge the 3 monos as follows (here they are RxJS Observables of course):
const somethings$ = source$
.filter(isSomething)
.do(something);
const betterThings$ = source$
.filter(isBetterThings)
.do(betterThings);
const defaultThings$ = source$
.filter((val) => !isSomething(val) && !isBetterThings(val))
.do(defaultThing);
// merge them together
const onlyTheRightThings$ = somethings$
.merge(
betterThings$,
defaultThings$,
)
.do(correctThings);
I have copied and pasted the relevant sample from the above article.
Consider that something$, betterThings$ and defaultThings$ are our monos isSomething & isBetterThings are the predicates.
Now here are my 3 real monos/publishers (written in java):
private Mono<ServerResponse> validateUser(User user) {
return Mono.just(new BeanPropertyBindingResult(user, User.class.getName()))
.doOnNext(err -> userValidator.validate(user, err))
.filter(AbstractBindingResult::hasErrors)
.flatMap(err ->
status(BAD_REQUEST)
.contentType(APPLICATION_JSON)
.body(BodyInserters.fromObject(err.getAllErrors()))
);
}
private Mono<ServerResponse> validateEmailNotExists(User user) {
return userRepository.findByEmail(user.getEmail())
.flatMap(existingUser ->
status(BAD_REQUEST)
.contentType(APPLICATION_JSON)
.body(BodyInserters.fromObject("User already exists."))
);
}
private Mono<ServerResponse> saveUser(User user) {
return userRepository.save(user)
.flatMap(newUser -> status(CREATED)
.contentType(APPLICATION_JSON)
.body(BodyInserters.fromObject(newUser))
);
}
Here is the top level method that needs to merge the three publishers:
public Mono<ServerResponse> signUpUser(ServerRequest serverRequest) {
return serverRequest.bodyToMono(User.class)
.mergeWith(...)
}
I am not sure how to use the mergeWith() operator... I have tried the Mono.when() static operator which takes several publishers (good for me) but returns a Mono<void> (bad for me).
Can anyone please help?
P.S. I am sure you will excuse the mix between RxJS (js) and Reactor code (java). I meant to use my knowledge from RxJS in order to achieve a similar goal in my Reactor app. :-)
edit 1: I have tried this:
public Mono<ServerResponse> signUpUser(ServerRequest serverRequest) {
return serverRequest
.bodyToMono(User.class)
.flatMap(user -> validateUser(user).or(validateEmailNotExists(user)).or(saveUser(user))).single();
}
But I get this error: NoSuchElementException: Source was empty
edit 2: Same with (notice the parenthesis):
public Mono<ServerResponse> signUpUser(ServerRequest serverRequest) {
return serverRequest
.bodyToMono(User.class)
.flatMap(user -> validateUser(user).or(validateEmailNotExists(user)).or(saveUser(user)).single());
}
edit 3: Same error with a Mono<User>:
public Mono<ServerResponse> signUpUser(ServerRequest serverRequest) {
Mono<User> userMono = serverRequest.bodyToMono(User.class);
return validateUser(userMono)
.or(validateEmailNotExists(userMono))
.or(saveUser(userMono))
.single();
}
edit 4: I can confirm that at least one of the three monos will always emit. It is when I use the or() operator that something goes wrong...
If I use this, all my tests pass:
public Mono<ServerResponse> signUpUser(ServerRequest serverRequest) {
return serverRequest.bodyToMono(User.class)
.flatMap(user -> Flux.concat(validateUser(user), validateEmailNotExists(user), saveUser(user)).next().single());
}
I have used the concat() operator here to preserve the order of operations.
Do you know what I am getting wrong with the or() operator?
edit 5: I have tried with the cache() operator as follows to no avail:
public Mono<ServerResponse> signUpUser(ServerRequest serverRequest) {
return serverRequest
.bodyToMono(User.class)
.cache()
.flatMap(user -> validateUser(user)
.or(validateEmailNotExists(user))
.or(saveUser(user))
.single()
);
}
Your current code sample implies that your 3 methods returning Mono<ServerResponse> should be taking a Mono<User> rather than a User, so you may need to alter something there.
However, I digress - that doesn't seem to be the main question here.
From what I understand of the pattern described in that link, you're creating 3 separate Mono objects, only one of which will ever return a result - and you need a Mono of whichever one of your original 3 Mono objects returns.
In that case, I'd recommend something like the following:
Mono<ServerResult> result = Flux.merge(validateUser(user), validateEmailNotExists(user), saveUser(user)).next().single();
Breaking it down:
The static Flux.merge() method takes your 3 Mono objects and merges them into a Flux;
next() returns the first available result as a Mono;
single() will ensure that the Mono emits a value, as oppose to nothing at all, and throw an exception otherwise. (Optional, but just a bit of a safety net.)
You could also just chain Mono.or() like so:
Mono<ServerResult> result = validateUser(user).or(validateEmailNotExists(user)).or(saveUser(user)).single();
The advantages to this approach are:
It's arguably more readable in some cases;
If it's possible that you'll have more than one Mono in your chain return a result, this allows you to set an order of precedence for which one is chosen (as oppose to the above example where you'll just get whatever Mono emitted a value first.)
The disadvantage is potentially one of performance. If saveUser() returns a value first in the above code, then you still have to wait for the other two Mono objects to complete before your combined Mono will complete.
We have a vertx verticle which receives an id and uses it see if an entity with the id exist in a database. It contains the following logic:
if (itemFound) {
e.onNext(item_which_was_found)
}
else {
e.onNext(null);
}
Another verticle has an Observable which processes a list of id's. It uses rxSend to pass each id in the list to the first verticle to do the database lookup:
Observable<Object> observable = ...
observable.flatMapSingle(id -> {
return rxSend(VERTICLE_1_ADDRESS, id);
})
.flatMapSingle ( i ->
{
// Logic dependent on if item was found
)
.subscribe();
With the above, it is easy to handle cases where the entity associated with the id was found in the database, because the first vertcle, in onNext(), returns the entity. The question is for the second case, when no entity exists and first verticle returns onNext(null). In this case, how is it possible to retrieve, in the second flatMapSingle, the item in the observable which is currently being processed (that is, the id which has no associated database entity) ? Or is there a better way to structure the code?
Thanks
You can change your observable definition to:
Observable<Object> observable = observable();
observable.flatMapSingle(id -> {
return rxSend(VERTICLE_1_ADDRESS, id).flatMap(i -> {
// Logic dependent on if item was found
// id is visible here
});
}).subscribe();
Then the id will be visible to your second lambda.
i am using the following rxjava dependencies in android:
compile 'io.reactivex.rxjava2:rxjava:2.1.0'
compile 'io.reactivex.rxjava2:rxandroid:2.0.1'
and i am trying to create a method that will take in a observer as a paramter. I am having some issues i think its because this is rxjava2 so things are updated and im a little confused.
Let me show you what i want to accomplish:
private Subscription subscription = Scriptions.empty(); //this isn't working. how to set a empty observer IN RXJAVA2?
protected abstract Observable buildUseCaseObservable(); //RETROFIT WILL BUILD THE OBSERVABLE FOR ME SOMEWHERE ELSE
public void execute(Consumer UseCaseSubscriber){
this.subscription = this.buildUseCaseObservable()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(UseCaseSubscriber); //THIS LINE IS NOT WORKING , ERROR IS IN THE PHOTO
}
public void unsubscribe(){
if(!subscription.isUnsubscribed()){
subscription.unsubscribe();
}
}
Basically i am trying to create a method that will accept a observer/consumer as parameter and use that to update the UI after retrofit is done (being the observable).
UPDATE:
ok i changed it to disposables. now i'd like to store the disposable that i get back but its not working.
protected abstract Observable buildUseCaseObservable();
#SuppressWarnings("unchecked")
public void execute(Observer UseCaseSubscriber){
this.subscription = this.buildUseCaseObservable()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(UseCaseSubscriber);
}
public void unsubscribe(){
if(!subscription.isUnsubscribed()){
subscription.unsubscribe();
}
}
i am getting the following warning:
The reason i want to store the whole thing in a subscription (or whatever else you recommend) is so i can unsubscribe to it whenever i want.
but from the docs:
Because Reactive-Streams base interface, org.reactivestreams.Publisher defines the subscribe() method as void, Flowable.subscribe(Subscriber) no longer returns any Subscription (or Disposable). The other base reactive types also follow this signature with their respective subscriber types.
so how to save disposable so we can unsubscribe then ?
Subscription has been 'renamed' to Disposable with 2.x version. You can read the rxJava wiki explanation on this change here.
so how to save disposable so we can unsubscribe then ? Flowable.subscribe(Subscriber) doesn't return disposable, but Observable.subscribe(Subscriber) does. If you don't need back-pressure, just cast your Flowable to Observable with .toObservable().
I have this the following scenario I need to achieve:
perform each network call for a list of request object with 1 second delay each
and I have this following implementation using rxjava2
emit an interval stream
emit an iterable stream
zip them to emit each item from the iterable source
which by far has no problem and I fully understand how it works, now I integrated the above to the following
map each item emitted from zip into a new observable that defer/postpone an observable source for a network call
each mapped-emitted observable will perform an individual network call for each request
which I ended up with the following code
Observable
.zip(Observable.interval(1, TimeUnit.SECONDS), Observable.fromIterable(iterableRequests), new BiFunction<Long, RequestInput, RequestResult>() {
#Override
public RequestResult apply(#NonNull Long aLong, #NonNull final RequestInput request) throws Exception {
return request;
}
})
.map(new Function<RequestResult, ObservableSource<?>>() {
#Override
public ObservableSource<?> apply(#NonNull RequestResult requestResult) throws Exception {
// map each requestResult into this observable and perform a new stream
return Observable
.defer(new Callable<ObservableSource<?>>() {
// return a postponed observable for each subscriber
})
.retryWhen(new Function<Observable<Throwable>, ObservableSource<?>>() {
// return throwable observable
})
}
})
.subscribe(new Observer<ObservableSource<?>>() {
//.. onSubscribe {}
//.. onError {}
//.. onComplete {}
#Override
public void onNext(ObservableSource<?> observableSource) {
// actual subscription for each of the Observable.defer inside
// so it will start to emit and perform the necessary operation
}
});
but the problem is, it executes the Observable.defer source, only ONCE, but keeps on iterating(by putting a Log inside the map operator to see the iteration).
Can anyone guide me please on how can I achieve what I want, I exhausted alot of papers, drawing alot of marble diagrams, just to see where Im at on my code,
I dont know if the diagram I created illustrate the thing that I want, if it does, I dont know why does the sample code dont perform as the diagram portraits
Any help would be greatly appreciated.
The first part is fine, but the map thingy is a bit unneeded, what you are doing is mapping each RequestResult to an Observable, and then manually subscribe to it at the Observer.onNext(), actually the defer is not necessary as you're creating separate Observable for each RequestResult with different data, defer will occur at each subscribe yoy do at onNext(), and the map occur as you observed for each emission of the zipped RequestResult.
what you probably need is simple flatMap() to map each RequestResult value to a separate Observable that will do the network request, and it will merge back the result for each request to the stream, so you'll just need to handle the final values emission for each request instead to subscribe manually to each Observable.
Just keep in mind that order might be lost, in case some requests might take longer than your delay between them.
Observable.zip(Observable.interval(1, TimeUnit.SECONDS), Observable.fromIterable(iterableRequests),
new BiFunction<Long, RequestInput, RequestResult>() {
#Override
public RequestResult apply(#NonNull Long aLong,
#NonNull final RequestInput request) throws Exception {
return request;
}
})
.flatMap(new Function<RequestResult, ObservableSource<?>>() {
#Override
public ObservableSource<?> apply(RequestResult requestResult) throws Exception {
return createObservableFromRequest(requestResult)
.retryWhen(new Function<Observable<Throwable>, ObservableSource<?>>() {
// return throwable observable
})
}
})
.subscribe(new Observer<ObservableSource<?>>() {
//.. onSubscribe {}
//.. onError {}
//.. onComplete {}
#Override
public void onNext(ObservableSource<?> observableSource) {
//do something with each network result request emission
}
});
I manage to make it work, as somewhere inside the Observable.defer, my retrofitclient was null,
retrofitClient.getApiURL().post(request); // client was null
my retrofitClient was null ( i looked somewhere in the code and I noticed i was not initialized, and I initialized it properly and made it work)
now can anybody tell me why Rx didnt throw an exception back to the original observable stream? theres no NullPointerException that occurred, Im confused
Playing with RxJava now and stumbled upon the following problem:
I have 2 different streams:
Stream with items
Stream (with just 1 item) which emits transformation information for the first stream.
So essentially I have stream of items and I want all those items to be combined with that single item from 2nd stream:
----a1----a2----a3----a4----a5----|--------------->
-------------b1--|----------------------------------->
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
------------a1b1-a2b1-a3b1-a4b1-a5b1-------->
It looks really similar to combileLatest operator, but combineLatest will ignore all items from the first stream except the closest to the item from the second stream. It means that I will not receive a1b1 - the first resulting item emitted is gonna be a2b1.
I also looked at delay operator, but it doesn't allow me to specify close stream like it is done with buffer operatior
Is there any fancy operator which solves the problem above?
There are several ways of making this happen:
1) flatMap over b if you don't need to start a upfront
b.flatMap(bv -> a.map(av -> together(av, bv)));
2) You can, of course, cache but it will retain your as for the entire duration of the stream.
3) Use groupBy a bit unconventionally because its GroupedObservable caches values until the single subscriber arrives, replays the cached value and continues as a regular direct observable (letting all previous cached values go).
Observable<Long> source = Observable.timer(1000, 1000, TimeUnit.MILLISECONDS)
.doOnNext(v -> System.out.println("Tick"))
.take(10);
Observable<String> other = Observable.just("-b").delay(5000, TimeUnit.MILLISECONDS)
.doOnNext(v -> System.out.println("Tack"))
;
source.groupBy(v -> 1)
.flatMap(g ->
other.flatMap(b -> g.map(a -> a + b))
).toBlocking().forEach(System.out::println);
It works as follows:
Get a hold onto a GroupedObservable by grouping everything from source into group 1.
when the group g arrives, we 'start observing' the other observable.
Once other fires its element, we take it and map it over the group and 'start observing' it as well, bringing us the final sequence of a + bs.
I've added doOnNexts so you can see the source is really active before the other fires its "Tack".
AFAIK, there is no a built-in operator to achieve the behavior you've described. You can always implement a custom operator or build it on top of existing operators. I think the second option is easier to implement and here is the code:
public static <L, R, T> Observable<T> zipper(final Observable<? extends L> left, final Observable<? extends R> right, final Func2<? super L, ? super R, ? extends T> function) {
return Observable.defer(new Func0<Observable<T>>() {
#Override
public Observable<T> call() {
final SerialSubscription subscription = new SerialSubscription();
final ConnectableObservable<? extends R> cached = right.replay();
return left.flatMap(new Func1<L, Observable<T>>() {
#Override
public Observable<T> call(final L valueLeft) {
return cached.map(new Func1<R, T>() {
#Override
public T call(final R valueRight) {
return function.call(valueLeft, valueRight);
}
});
}
}).doOnSubscribe(new Action0() {
#Override
public void call() {
subscription.set(cached.connect());
}
}).doOnUnsubscribe(new Action0() {
#Override
public void call() {
subscription.unsubscribe();
}
});
}
});
}
If you have any questions regarding the code, I can explain it in details.
UPDATE
Regarding the questing how my solution is different from the following one:
left.flatMap(valueLeft -> right.map(valueRight -> together(valueLeft, valueRight)));
Parallel execution - in my implementation both left and right observables are executing in parallel. right observable doesn't have to wait for a left one to emit its first item.
Caching - my solution subscribes only once to the right observables and caches its result. Thats why b1 will always be the same for all aXXX items. The solution provided by akarnokd subscribes to the rightobservable every time the left one emits an item. That means:
There is no guarantee that b1 won't change its value. For example for the following observable you will get a different b for each a.
final Observable<Double> right = Observable.defer(new Func0<Observable<Double>>() {
#Override
public Observable<Double> call() {
return Observable.just(Math.random());
}
});
If the right observable is a time consuming operation (e.g. network call), you will have to wait for its completion every time the left observable emits a new item.