Flux does not wait for completion of elements before 'then' - java

I am failing to understand the issue and I am not sure what am I doing wrong.
I want to wait for Flux to end and then return Mono of serverResponse
I have attached the code snippet, the doOnNext will populate the categoryIdToPrintRepository.
I have looked around on how to return mono after flux ends and found the 'then' but still the 'then' method is being executed way before the onNextSite is being processed, this results with the error:
java.lang.IllegalArgumentException: 'producer' type is unknown to ReactiveAdapterRegistry
What am I doing wrong?
public Mono<ServerResponse> retrieveCatalog(ServerRequest ignored) {
return Mono.just("start").flatMap(id ->
Flux.fromIterable(appSettings.getSites())
.subscribeOn(ForkJoinPoolScheduler.create("SiteCatalogScheduler"))
.doOnNext(this::onNextSite)
.then(Mono.from(ServerResponse.ok().body(categoryIdToPrintRepository.getSortedTreeValues(), String.class))));
}
private void onNextSite(Integer siteId) {
IntStream.range(1, appSettings.getCatalogMaxValue()).parallel().forEach(catalogId -> {
Optional<SiteCatalogCategoryDTO> cacheData =
siteCatalogCacheUseCaseService.getSiteCatalogResponseFromCache(siteId, catalogId);
cacheData.ifPresentOrElse(siteCatalogCategoryDTO -> {/*do nothing already exist in cache*/},
() -> {
Mono<SiteCatalogCategoryDTO> catalogCategoryDTOMono = WebClient.create(getUri(siteId, catalogId))
.get().retrieve().bodyToMono(SiteCatalogCategoryDTO.class);
catalogCategoryDTOMono.subscribe(siteCatalogCategoryDTO ->
handleSiteServerResponse(siteCatalogCategoryDTO, siteId, catalogId));
});
});
}
private void handleSiteServerResponse(SiteCatalogCategoryDTO siteCatalogCategoryDTO,
int siteId, int catalogId) {
if (siteCatalogCategoryDTO.getResponseStatus().equals(ResponseStatus.SUCCESS))
Flux.fromIterable(siteCatalogCategoryDTO.getMappingList())
.subscribe(mapSCC -> {
categoryIdToPrintRepository.insertIntoTree(mapSCC.getCategoryId(),
"Site " + siteId + " - Catalog " + catalogId + " is mapped to category " + "\"" +
mapSCC.getCategoryName() + "\" (" + mapSCC.getCategoryId() + ")");
siteCatalogCacheUseCaseService.insertIntoSiteCatalogCache(siteId, catalogId, siteCatalogCategoryDTO);
});
}

You are doing several things wrong you should not subscribe in your application, and you are having void methods, which should not be used in reactive programming unless in specific places.
here is some example code:
// Nothing will happen, we are not returning anything, we can't subscribe
private void doSomething() {
Mono.just("Foo");
}
// complier error
doSomething().subscribe( ... );
Your application is a publisher the calling client, is the subscriber, thats why we return a Mono or a Flux out to the calling client, they subscribe.
You have solved it this way:
private void doSomething() {
Mono.just("Foo").subscribe( ... );
}
doSomething();
Now you are subscribing to yourself to get things running, this is not the correct way, as mentioned before, the calling client is the subscriber, not you.
Correct way:
private Mono<String> doSomething() {
return Mono.just("Foo");
}
// This is returned out to the calling client, they subscribe
return doSomething();
As a Mono/Flux completes, it will emit a signal, this signal will trigger the next and the next and the next in the chain.
So my opinion of what you need to do is the following:
Remove all subscribes, if you want to do things there are functions like, flatmap, map, doOnSuccess etc. keep the chain instact all the way out to the client.
Remove all void functions, make sure they return a Flux or a Mono and if you want to not return something return a Mono<Void> by using the Mono.empty() function so that the chain will be complete.
As soon as you use a Mono/Flux you need to handle the return so that others can chain on.
Update:
In order for then to trigger, you must return something, it will return when the previous mono/flux completes.
example:
private Flux<String> doSomething() {
return Flux.just("Foo", "Bar", "FooBar")
.doOnNext(string -> {
return // return something
});
}
// Ignore what was return from doSomething and return something else when the flux has completed (so only trigger on the completed signal from the flux)
return doSomething().then( ... );

Related

How to prevent Mono from being cancelled?

I am trying to implement something as a "race condition". This race condition must follow these situations:
Fire two simultaneous HTTP calls.
Return the response from the first call that was completed successfully.
Handle the last call. (The most important thing here is that I can not discard the last call, I do need to handle the result of it: whatever its status, success or fail).
This sample of code is the most close of the solution that I have achieved:
Mono<StatusMock> monoA = webClient.get()
.uri("https://some.url.a")
.retrieve()
.bodyToMono(StatusMock.class)
.subscribeOn(Schedulers.boundedElastic());
Mono<StatusMock> monoB = webClient.get()
.uri("https://some.url.b")
.retrieve()
.bodyToMono(StatusMock.class)
.doOnSuccess(this::verifyBody)
.onErrorStop()
.subscribeOn(Schedulers.boundedElastic());
StatusMock statusMock = Flux.first(monoA, monoB)
.blockFirst();
if (statusMock != null) {
return statusMock.getStatus();
}
return "empty";
}
private void verifyBody(StatusMock statusMock) {
if (statusMock.getStatus().contains("error")) {
log.error("throwing an exception");
throw new RuntimeException("error");
}
}
public class StatusMock {
private String status; // getters and setters implicit
}
In this example I used the Flux.first method, and it helps me a lot returning the first call, but it discards (cancel) the second one which is a problem since I need the result of the last call as well.
Is there any solution to this logic? Here I am using Spring Project Reactor, but I accept any library or framework that could help me with this situation.
You can use cache operator on the Monos to prevent them from being cancelled:
Mono<StatusMock> monoA = webClient.get()
// ...
.cache();
Mono<StatusMock> monoB = webClient.get()
// ...
.cache();
Mono.firstWithSignal(monoA, monoB);

Nesting CompletionStages in Java to make inner blocks run before outer blocks

I've written a method like below:
public static CompletionStage<Tuple2<ObjectNode, String>> calculateTemplateTreeAndKeys(
String content,
RequestContext context,
MetricsClient metricsClient,
JdbcSession jdbcSession) {
AtomicReference<ObjectNode> templateTreeHolder = new AtomicReference<>();
templateTreeHolder.set(Json.rootNode());
return getTemplateIds(context, metricsClient, jdbcSession, content)
.thenCompose(
templateIds -> {
templateIds.map(
id ->
// do something and return CompletionStage<String>
.thenAccept(
tree -> {
templateTreeHolder.set(
(ObjectNode)
templateTreeHolder.get().set(id, Json.readTree(tree)));
System.out.println(
"From inner function: " + templateTreeHolder.get());
}));
return CompletableFuture.completedFuture(NotUsed.getInstance());
})
.thenApply(
notUsed -> {
String includedTemplateIdsStr =
getKeysFromTemplateTree(templateTreeHolder.get()).toJavaList().toString();
System.out.println("From outer function: " + templateTreeHolder.get());
return Tuple.of(templateTreeHolder.get(), includedTemplateIdsStr);
});
I expect the inner block to process and update templateTreeHolder before
.thenApply is invoked, so that templateTreeHolder would hold correct data to return. But, .thenApply block is processing before the inner .thenAccept block.
From the console output sequence:
From outer function: {}
From inner function: {"f9406341-c62a-411a-9389-00a62bd63629":{}}
I'm not sure what I'm doing wrong on chaining CompletionStages, kindly advise me how can I make sure that the inner block completes before the outer block?
Your function passed to thenCompose is returning an already complete future, i.e. return CompletableFuture.completedFuture(NotUsed.getInstance()); which allows the dependent stages to proceed immediately. This seem to conflict with the evaluation of the function passed to templateIds.map(…), which happens asynchronously, apparently.
Generally, you should avoid such mixture of completion stages and dependencies to side effects, especially when their asynchronous evaluation is not modeled as prerequisite completion stage.
But you can work-around this, if you have no other choice:
return getTemplateIds(context, metricsClient, jdbcSession, content)
.thenCompose(
templateIds -> {
// create an initially uncompleted stage
CompletableFuture<Object> subStage = new CompletableFuture<>();
templateIds.map(
id ->
// do something and return CompletionStage<String>
.thenAccept(
tree -> {
templateTreeHolder.set(
(ObjectNode)
templateTreeHolder.get().set(id, Json.readTree(tree)));
System.out.println(
"From inner function: " + templateTreeHolder.get());
// complete when all work has been done
subStage.complete(null);
}));
// use this stage for dependent actions
return subStage;
})
.thenApply(
notUsed -> {
String includedTemplateIdsStr =
getKeysFromTemplateTree(templateTreeHolder.get()).toJavaList().toString();
System.out.println("From outer function: " + templateTreeHolder.get());
return Tuple.of(templateTreeHolder.get(), includedTemplateIdsStr);
});
In the code above, the future will never get completed if your action fails with an exception before the completion attempt. The general pattern would be like this:
CompletableFuture<Type> stage = new CompletableFuture<>();
…
try {
code that will eventually call complete on stage
}
catch(Throwable t) {
stage.completeExceptionally(t);
}
But, of course, it will get a bit more complicated when the code supposed to complete the stage also bears asynchronous processing, so you have to guard the code trying to submit the actual completion code, as well as the actual completion code.
So, a more elaborated version of the inner code would look like:
CompletableFuture<Object> subStage = new CompletableFuture<>();
try {
templateIds.map(
id ->
// do something and return CompletionStage<String>
.thenAccept(
tree -> {
templateTreeHolder.set(
(ObjectNode)
templateTreeHolder.get().set(id, Json.readTree(tree)));
System.out.println(
"From inner function: " + templateTreeHolder.get());
})
.whenComplete((v,t) -> {
// complete when all work has been done
if(t != null) subStage.completeExceptionally(t);
else subStage.complete(v);
}));
} catch(Throwable t) {
subStage.completeExceptionally(t);
}
// use this stage for dependent actions
return subStage;
(perhaps, the “do something and return CompletionStage” has to be guarded with try { … } catch(Throwable t) { subStage.completeExceptionally(t); } too)

Java short circuit CompletableFuture

I am trying to find a way to skip CompletableFuture based on specific conditions.
For example
public CompletableFuture<Void> delete(Long id) {
CompletableFuture<T> preFetchCf = get(id);
CompletableFuture<Boolean> cf1 = execute();
/*This is where I want different execution path, if result of this future is true go further, else do not*/
// Execute this only if result of cf1 is true
CompletableFuture<T> deleteCf = _delete(id);
// Execute this only if result of cf1 is true
CompletableFuture<T> postDeleteProcess = postDelete(id);
}
What is a good way to achieve this ?
I will prepare a different example than the one you used in the question, because your code is not quite clear in intent from the readers perspective.
First suppose the existing of a CompletableFuture<String> that provides the name of a Star Wars characters.
CompletableFuture<String> character = CompletableFuture.completedFuture("Luke");
Now, imagine I have two other CompletableFuture that represent different paths I may want to follow depending on whether the first completable future provides a character that is a Jedi.
Supplier<CompletableFuture<String>> thunk1 = () -> CompletableFuture.completedFuture("This guy is a Jedi");
Supplier<CompletableFuture<String>> thunk2 = () -> CompletableFuture.completedFuture("This guy is not a Jedi");
Notice that I wrapped the CompletableFuture in a a Supplier, to avoid that they get eagerly evaluated (this is concept known as thunk).
Now, I go and to my asynchronous chain:
character.thenApply(c -> isJedi(c))
.thenCompose(isJedi -> isJedi ? thunk1.get() : thunk2.get())
.whenComplete((answer, error) -> System.out.println(answer));
The use of thenCompose let me choose a path based on the boolean result. There I evaluate one of the thunks and cause it to create a new CompletableFuture for the path I care about.
This will print to the screen "This guys is a Jedi".
So, I believe what you're looking for is the thenCompose method.
Not sure if I understand your objective, but why won't you just go with future chaining like you said in the comment? Something like this, just to illustrate:
public class AppTest {
#Test
public void testCompletableFutures() {
Integer id = (int) Math.random() * 1000;
CompletableFuture<Void> testing = AppTest.execute()
.thenAcceptAsync(result -> {
System.out.println("Result is: " + result);
if(result)
AppTest.delete(id);
else
throw new RuntimeException("Execution failed");
})
.thenApplyAsync(result -> AppTest.postDelete())
.thenAcceptAsync(postDeleteResult -> {
if(postDeleteResult)
System.out.println("Post delete cleanup success");
else
throw new RuntimeException("Post delete failed");
});
}
private static boolean postDelete() {
System.out.println("Post delete cleanup");
return Math.random() > 0.3;
}
private static CompletableFuture<Boolean> delete(int i) {
System.out.println("Deleting id = " + i);
return CompletableFuture.completedFuture(true);
}
private static CompletableFuture<Boolean> execute() {
return CompletableFuture.supplyAsync(() -> Math.random() > 0.5);
}
}
Of course that doesn't make much real-life sense, but I think it works to show a concept.
If you want to skip the second call after execute based on the result it's clearly not possible since you need that result. The point is that it should not matter for you whether you skipped that or not since it's asynchronous, you are not blocking to wait for that result.

rxjava2 - if else on Maybe

I am looking for what is the recommended practice in rxjava2 to handle a case where one flowable leads to conditional behaviors.
More concretely, I have a Maybe<String> for which I want to Update the String on the database if the String exists or, if it doesn't exists I want to create a new String and save it on the database.
I thought of the below but obviously it is not what I am looking for:
Maybe<String> source = Maybe.just(new String("foo")); //oversimplified source
source.switchIfEmpty(Maybe.just(new String("bar"))).subscribe(result ->
System.out.println("save to database "+result));
source.subscribe(result -> System.out.println("update result "+result));
The above obviously produces
save to database foo
update result foo
I tried also the below which gives the expected result but still feel it's... weird.
Maybe<String> source = Maybe.just(new String("foo")); //oversimplified source
source.switchIfEmpty(Maybe.just(new String("bar")).doOnSuccess(result ->
System.out.println("save to database "+result))).subscribe();
source.doOnSuccess(result -> System.out.println("update result "+result)).subscribe();
How can I have an action for when the result exists and when it doesn't exists? How is that use case supposed to be handled in rxjava2?
Update 01
I tried the below and it looks cleaner than what I came up with above. Note sure it is recommended rxjava2 practice however...
Maybe.just(new String("foo"))
.map(value -> Optional.of(value))
.defaultIfEmpty(Optional.empty())
.subscribe(result -> {
if(result.isPresent()) {
System.out.println("update result "+result);
}
else {
System.out.println("save to database "+"bar");
}
});
You have the isEmpty() operator that will return you Boolean if the Maybe source is empty or not, and then you can flatMap it and write a if else statement depending on that Boolean
This is a common pattern in our code as well, though in our case the choices are themselves async. You can't get quite the right semantic by simply composing flatMapX and switchIfEmpty (in either order), so I am curious why this isn't part of the API.
Here's what we're doing for now (this example for when the 2 options are both Completables, we have similar things for the other types as well):
public static <T> Completable flatMapCompletable(Maybe<T> target,
#ClosureParams(FirstParam.FirstGenericType.class)
Closure<? extends CompletableSource> completableSupplier,
Supplier<CompletableSource> emptySupplier) {
Maybe<T> result = target.cache();
return result.isEmpty().flatMapCompletable(empty -> {
if (empty) {
return emptySupplier.get();
} else {
return result.flatMapCompletable(completableSupplier::call);
}
});
}
We're using Groovy, so we package these up as extension methods. I'm not thrilled with the need to use cache() so I'm wondering if there is a better alternative. From looking at the code, an operator which basically combines flatMapX and switch looks like it wouldn't be too hard (but I feel like I'm missing something).
Try something like this. checkDB can return a Maybe or Single or whatever which emits either an optional or a wrapper Object.
checkDB(String)
.flatMap(s -> {
if (s.isPresent()) {
return updateDB(s.get());
} else {
return insertDB("new String");
}
})
There is an solution using the flatMap call with 3 params
fun addOrUpdate(message: LocalMessage): Single<LocalMessage> {
return getById(message.id) // returns Maybe
.flatMap(
Function {
update(message) // onSuccess update call returns Single
},
Function {
Single.error(it) // onError
},
Callable {
add(message) // onComplete add call returns Single
}
)
}
}
Or shorter version
fun addOrUpdate(message: LocalMessage): Single<LocalMessage> {
return getById(message.id) // returns Maybe
.flatMap(
{
update(message) // onSuccess update call returns Single
},
{
Single.error(it) // onError
},
{
add(message) // onComplete add call returns Single
}
)
}
}

RxJava: Find out if BehaviorSubject was a repeated value or not

I'm making an Android interface that shows some data fetched from the network. I want to have it show the latest available data, and to never be empty (unless no data has been fetched at all yet) so I'm using a BehaviorSubject to give subscribers (my UI) the latest available info, while refreshing it in the background to update it.
This works, but due to another requirement in my UI, I now have to know whether or not the published result was gotten fresh from the network or not. (In other words, I need to know if the published result was BehaviorSubject's saved item or not.)
How can I achieve this? If I need to split it up into multiple Observables, that's fine, as long as I'm able to get the caching behavior of BehaviorSubject (getting the last available result) while also being able to tell if the result returned was from the cache or not. A hacky way I can think of to do it would be to check if the timestamp of the response was relatively soon, but that'd be really sloppy and I'd rather figure out a way to do it with RxJava.
As you mentioned in the question, this can be accomplished with multiple Observables. In essence, you have two Observables: "the fresh response can be observed", and "the cached response can be observed". If something can be "observed", you can express it as an Observable. Let's name the first one original and the second replayed.
See this JSBin (JavaScript but the concepts can be directly translated to Java. There isn't a JavaBin as far as I know, for these purposes).
var original = Rx.Observable.interval(1000)
.map(function (x) { return {value: x, from: 'original'}; })
.take(4)
.publish().refCount();
var replayed = original
.map(function (x) { return {value: x.value, from: 'replayed'}; })
.replay(null, 1).refCount();
var merged = Rx.Observable.merge(original, replayed)
.replay(null, 1).refCount()
.distinctUntilChanged(function (obj) { return obj.value; });
console.log('subscribe 1st');
merged.subscribe(function (x) {
console.log('subscriber1: value ' + x.value + ', from: ' + x.from);
});
setTimeout(function () {
console.log(' subscribe 2nd');
merged.subscribe(function (x) {
console.log(' subscriber2: value ' + x.value + ', from: ' + x.from);
});
}, 2500);
The overall idea here is: annotate the event with a field from indicating its origin. If it's original, it's a fresh response. If it's replayed, it's a cached response. Observable original will only emit from: 'original' and Observable replayed will only emit from: 'replayed'. In Java we would require a bit more boilerplate because you need to make a class to represent these annotated events. Otherwise the same operators in RxJS can be found in RxJava.
The original Observable is publish().refCount() because we want only one instance of this stream, to be shared with all observers. In fact in RxJS and Rx.NET, share() is an alias for publish().refCount().
The replayed Observable is replay(1).refCount() because it is also shared just like the original one is, but replay(1) gives us the caching behavior.
merged Observable contains both original and replayed, and this is what you should expose to all subscribers. Since replayed will immediately emit whenever original does, we use distinctUntilChanged on the event's value to ignore immediate consecutives. The reason we replay(1).refCount() also the merged is because we want the merge of original and replay also to be one single shared instance of a stream shared among all observers. We would have used publish().refCount() for this purpose, but we cannot lose the replay effect that replayed contains, hence it's replay(1).refCount(), not publish().refCount().
Doesn't Distinct cover your case? BehaviorSubject only repeats the latest element after subscription.
I believe what you want is something like this:
private final BehaviorSubject<T> fetched = BehaviorSubject.create();
private final Observable<FirstTime<T>> _fetched = fetched.lift(new Observable.Operator<FirstTime<T>, T>() {
private AtomicReference<T> last = new AtomicReference<>();
#Override
public Subscriber<? super T> call(Subscriber<? super FirstTime<T>> child) {
return new Subscriber<T>(child) {
#Override
public void onCompleted() {
child.onCompleted();
}
#Override
public void onError(Throwable e) {
child.onError(e);
}
#Override
public void onNext(T t) {
if (!Objects.equals(t, last.getAndSet(t))) {
child.onNext(FirstTime.yes(t));
} else {
child.onNext(FirstTime.no(t));
}
}
};
}
});
public Observable<FirstTime<T>> getObservable() {
return _fetched;
}
public static class FirstTime<T> {
final boolean isItTheFirstTime;
final T value;
public FirstTime(boolean isItTheFirstTime, T value) {
this.isItTheFirstTime = isItTheFirstTime;
this.value = value;
}
public boolean isItTheFirstTime() {
return isItTheFirstTime;
}
public T getValue() {
return value;
}
public static <T> FirstTime<T> yes(T value) {
return new FirstTime<>(true, value);
}
public static <T> FirstTime<T> no(T value) {
return new FirstTime<>(false, value);
}
}
The wrapper class FirstTime has a boolean which can be used to see if any subscriber to the Observable has seen it before.
Hope that helps.
Store the information of BehaviorSubject objects in a data structure with a good lookup such as a Dictionnary. Each value would be a key and the value would be the number of iteration.
There so, when you look at a particulary key, if your dictionnary contains it already and its value is already at one, then you know that a value is a repeated value.
I'm not really sure what you want to achieve. Probably you'd just like to have a smart source for the "latest" data and a second source which tells you when the data was refreshed?
BehaviorSubject<Integer> dataSubject = BehaviorSubject.create(42); // initial value, "never empty"
Observable<String> refreshedIndicator = dataSubject.map(data -> "Refreshed!");
refreshedIndicator.subscribe(System.out::println);
Observable<Integer> latestActualData = dataSubject.distinctUntilChanged();
latestActualData.subscribe( data -> System.out.println( "Got new data: " + data));
// simulation of background activity:
Observable.interval(1, TimeUnit.SECONDS)
.limit(100)
.toBlocking()
.subscribe(aLong -> dataSubject.onNext(ThreadLocalRandom.current().nextInt(2)));
Output:
Refreshed!
Got new data: 42
Refreshed!
Got new data: 0
Refreshed!
Refreshed!
Refreshed!
Got new data: 1
Refreshed!
Got new data: 0
Refreshed!
Got new data: 1

Categories

Resources