Spring Reactor: adding delay but in an NON blocking way - java

Small question on how to add delay in a method but in a non blocking way please.
A very popular way to simulate long processes is to use Thread.sleep();
However, for project Reactor, this is a blocking operation.
And it is well known, in a reactive project, we should not block.
I would like to experiment and simulate long processes. Some sort of method which will take a lot of time, but in a NON blocking way, WITHOUT swapping thread. This is to simulate a method that is just vey lengthy, but proven NON blocking by BlockHound etc.
This construct is very popular:
#Test
public void simulateLengthyProcessingOperationReactor() {
Flux.range(1,5000)
.map(a -> simulateLengthyProcessingOperation(a))
.subscribe(System.out::println);
}
public String simulateLengthyProcessingOperation(Integer input) {
simulateDelayBLOCKING();
return String.format("[%d] on thread [%s] at time [%s]", input, Thread.currentThread().getName(), new Date());
}
public void simulateDelayBLOCKING() {
try {
Thread.sleep(4000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
But it is blocking.
(I know there is the Mono.fromCallable(() -> but this is not the question)
Is it possible to do the same, simulate delay, but NON blocking please?
Also, .delay will not achieve the expected result (simulating a NON blocking lengthy method on the same reactive pipeline)
#Test
public void simulateLengthyProcessingOperationReactor() {
Flux.range(1,5000)
.map(a -> simulateLengthyProcessingOperation(a))
.subscribe(System.out::println);
}
public String simulateLengthyProcessingOperation(Integer input) {
simulateDelay_NON_blocking();
return String.format("[%d] on thread [%s] at time [%s]", input, Thread.currentThread().getName(), new Date());
}
public void simulateDelay_NON_blocking() {
//simulate lengthy process, but WITHOUT blocking
}
Thank you

Of course you can, there is a family of methods .delay...()
You can for example read about delayElements() method here:
https://projectreactor.io/docs/core/release/api/reactor/core/publisher/Flux.html#delayElements-java.time.Duration-
You should know that it switches the executing thread to another Scheduler.
Signals are delayed and continue on the parallel default Scheduler.
In simplest case it would look like this:
public void simulateLengthyProcessingOperationReactor() {
Flux.range(1,5000)
.delayElements(Duration.ofMillis(1000L)) // delay each element for 1000 millis
.subscribe(System.out::println);
}
According to your case you could write your code like this:
#Test
public void simulateLengthyProcessingOperationReactor() {
Flux.range(1,5000)
.concatMap(this::simulateDelay_NON_blocking)
.subscribe(System.out::println);
}
public Mono<String> simulateDelay_NON_blocking(Integer input) {
//simulate lengthy process, but WITHOUT blocking
return Mono.delay(Duration.ofMillis(1000L))
.map(__ -> String.format("[%d] on thread [%s] at time [%s]",
input, Thread.currentThread().getName(), new Date()));
}

Related

Asynchronously waiting for a condition

I would like to wait for a condition asynchronously. Below is an example using awaitility library however, as far as I know, awaitility is blocking (i.e not async). Any ideas on how to achieve this in an async way natively (or with another lib maybe). Any ideas are appreciated.
await().forever().with().pollInterval(1, TimeUnit.SECONDS)
.until(() -> redis.eval(lockscript, ScriptOutputType.BOOLEAN, "mutex:" + key).equals(true));
await().atMost(timeout, TimeUnit.SECONDS).with().pollInterval(1, TimeUnit.SECONDS).until(
() -> redis.eval(lockscript, ScriptOutputType.BOOLEAN, "mutex:" + key).equals(true));
As mentioned in the comments, you can play around with Completable Futures and a Scheduled Executor to get what you want (or at least something close to that).
We can define a method until like so:
public void until(Callable<Boolean> method, long timeout, TimeUnit unit, ScheduledExecutorService s) throws Exception {
s.scheduleAtFixedRate(() -> {
try {
Boolean returnVal = method.call();
if (returnVal == true)
s.shutdown();
} catch (Exception e) {
e.printStackTrace();
}
}, timeout, timeout, unit);
}
What this does is take a passed scheduledExecutor and invoke any Callable method (in this case with a return value Boolean since this is what you want. This will loop every timeout until the requirement is met and the scheduler is shutdown.
Note: If you want to re-use the scheduler, do not call shutdown() on it, but rather cancel().
The way we call this is as follows:
ScheduledExecutorService sched = new ScheduledThreadPoolExecutor(1);
until(() -> basicBoolStatement(), 1, TimeUnit.SECONDS, sched);
We don't need the scheduler to have more than one thread. Just pass in anything else that returns a boolean for basicBoolStatement().
If you want to give a time limit to your request, then you can do the additional call, like so:
public static void untilAtMost(Callable<Boolean> method, long untilTimeout, long atMostTimeout, TimeUnit unit, ScheduledExecutorService s) throws Exception {
CompletableFuture.runAsync(() -> {
try {
until(method, untilTimeout, unit, s);
} catch (Exception e) {
e.printStackTrace();
}
});
ScheduledExecutorService sched = new ScheduledThreadPoolExecutor(1);
sched.schedule(() -> {
s.shutdown();
sched.shutdown();
}, atMostTimeout, unit);
}
Here, we re-use the until method above, but we have another scheduler that will shutdown() the until scheduler when the atMostTimeout time passes.
And in the same way, the calling code would look something like:
ScheduledExecutorService sched = new ScheduledThreadPoolExecutor(1);
untilAtMost(() -> basicBoolStatement(), 10, 1, TimeUnit.SECONDS, sched);
Edit: If you don't want to handle exceptions the way it is with the Callable interface, you can use a Supplier.
Disclaimer: sorry for the messy code, but this is just a proof of concept.

Main thread is not waiting for subscribers to finish their task in reactive subscriber

I have a service in spring which needs to fetch data using ten different methods.
I would like to have these methods execute parallelly to do some DB operations and return to the parent thread. But the parent thread should wait until all the responses come and then return a response.
In my current approach, I am using reactive mono to execute all methods asynchronously but the main thread is not waiting for the subscriber methods to finish.
Below are my two methods which I have subscribed
private Mono<BaseResponse> getProfileDetails(long profileId){
return new Mono<BaseResponse>() {
#Override
public void subscribe(Subscriber<? super BaseResponse> s) {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// DB Operation
System.out.println("Inside getProfileDetails");
s.onNext(new BaseResponse());
}
};
}
private Mono<Address> getAddressDetails(long profileId){
return new Mono<Address>() {
#Override
public void subscribe(Subscriber<? super Address> s) {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// DB Operation
System.out.println("Inside getAddressDetails");
s.onNext(new Address());
}
};
}
And below is my main method
public BaseResponse getDetails(long profileId){
ExecutorService executors = Executors.newFixedThreadPool(2);
Mono<BaseResponse> profileDetail = this.getProfileDetails(profileId).subscribeOn(Schedulers.fromExecutor(executors));
Mono<BaseResponse> addressDetail = this.getAddressDetails(profileId).subscribeOn(Schedulers.fromExecutor(executors));
List<BaseResponse> list = new ArrayList<>();
profileDetail.mergeWith(addressDetail)
.subscribe(consumer -> {
list.add(consumer);
});
System.out.println("list: "+new Gson().toJson(list));
executors.shutdown();
return response;
}
Below is my output:
list: []
Inside getProfileDetails
Inside getAddressDetails
My output shows that the main thread is not waiting for the subscriber to finish its task,
so how can I handle this situation?
I'm assuming your getProfileDetails() and getAddressDetails() methods are just placeholders, as they don't make much sense as written.
That being said, if this is your entire application here, and you genuinely just want to block before completing, you may as well just change your current subscribe() call for a doOnNext(), then just blockLast():
profileDetail.mergeWith(addressDetail)
.doOnNext(consumer -> {
list.add(consumer);
})
.blockLast();
Blocking on reactive threads is usually ill-advised in reactive applications for good reason, but in this case you literally just want to block before exiting outright - so I can't see much downside here.

Run IO computations in parallel in Java8

I'm familiar with functional programming languages, usually in Scala and Javascript. I'm working on a Java8 project and not sure how I am supposed to run through a list/stream of item, and perform some side-effect for each of them in parallel, using a custom thread pool, and return an object on which it's possible to listen for completion (wether it's a success or failure).
Currently I have the following code, it seems to work (I'm using Play framework Promise implementation as return) but it seems not ideal because ForkJoinPool is not meant to be used for IO intensive computations in the first place.
public static F.Promise<Void> performAllItemsBackup(Stream<Item> items) {
ForkJoinPool pool = new ForkJoinPool(3);
ForkJoinTask<F.Promise<Void>> result = pool
.submit(() -> {
try {
items.parallel().forEach(performSingleItemBackup);
return F.Promise.<Void>pure(null);
} catch (Exception e) {
return F.Promise.<Void>throwing(e);
}
});
try {
return result.get();
} catch (Exception e) {
throw new RuntimeException("Unable to get result", e);
}
}
Can someone give me a more idiomatic implementation of the above function? Ideally not using the ForkJoinPool, using a more standard return type, and most recent Java8 APIs? Not sure what I'm supposed to use between CompletableFuture, CompletionStage, ForkJoinTask...
A canonical solution would be
public static CompletableFuture<Void> performAllItemsBackup(Stream<Item> items) {
ForkJoinPool pool = new ForkJoinPool(3);
try {
return CompletableFuture.allOf(
items.map(CompletableFuture::completedFuture)
.map(f -> f.thenAcceptAsync(performSingleItemBackup, pool))
.toArray(CompletableFuture<?>[]::new));
} finally {
pool.shutdown();
}
}
Note that the interaction between ForkJoin pool and parallel streams is an unspecified implementation detail you should not rely on. In contrast, CompletableFuture provides a dedicated API for providing an Executor. It doesn’t even have to be a ForkJoinPool:
public static CompletableFuture<Void> performAllItemsBackup(Stream<Item> items) {
ExecutorService pool = Executors.newFixedThreadPool(3);
try {
return CompletableFuture.allOf(
items.map(CompletableFuture::completedFuture)
.map(f -> f.thenAcceptAsync(performSingleItemBackup, pool))
.toArray(CompletableFuture<?>[]::new));
} finally {
pool.shutdown();
}
}
In either case, you should shut down the executor explicitly instead of relying on automatic cleanup.
If you need a F.Promise<Void> result, you can use
public static F.Promise<Void> performAllItemsBackup(Stream<Item> items) {
ExecutorService pool = Executors.newFixedThreadPool(3);
try {
return CompletableFuture.allOf(
items.map(CompletableFuture::completedFuture)
.map(f -> f.thenAcceptAsync(performSingleItemBackup, pool))
.toArray(CompletableFuture<?>[]::new))
.handle((v, e) -> e!=null? F.Promise.<Void>throwing(e): F.Promise.pure(v))
.join();
} finally {
pool.shutdown();
}
}
But note that this, like your original code, only returns when the operation has been completed, while the methods returning a CompletableFuture allow the operations to run asynchronously until the caller invokes join or get.
To return a truly asynchronous Promise, you have to wrap the entire operation, e.g.
public static F.Promise<Void> performAllItemsBackup(Stream<Item> stream) {
return F.Promise.pure(stream).flatMap(items -> {
ExecutorService pool = Executors.newFixedThreadPool(3);
try {
return CompletableFuture.allOf(
items.map(CompletableFuture::completedFuture)
.map(f -> f.thenAcceptAsync(performSingleItemBackup, pool))
.toArray(CompletableFuture<?>[]::new))
.handle((v, e) -> e!=null? F.Promise.<Void>throwing(e): F.Promise.pure(v))
.join();
} finally {
pool.shutdown();
}
});
}
But it’s better to decide for one API instead of jumping back and forth between two different APIs.

How to test non-RxJava observables or async code in general?

I'm playing around with implementing my own observables or porting them from other languages for fun and profit.
The problem I've run into is that there's very little info on how to properly test observables or async code in general.
Consider the following test code:
// Create a stream of values emitted every 100 milliseconds
// `interval` uses Timer internally
final Stream<Number> stream =
Streams.interval(100).map(number -> number.intValue() * 10);
ArrayList<Number> expected = new ArrayList<>();
expected.add(0);
expected.add(10);
expected.add(20);
IObserver<Number> observer = new IObserver<Number>() {
public void next(Number x) {
assertEquals(x, expected.get(0));
expected.remove(0);
if(expected.size() == 0) {
stream.unsubscribe(this);
}
}
public void error(Exception e) {}
public void complete() {}
};
stream.subscribe(observer);
As soon as the stream is subscribed to, it emits the first value. onNext is called... And then the test exits successfully.
In JavaScript most test frameworks nowadays provide an optional Promise to the test case that you can call asynchronously on success/failure. Is anything similar available for Java?
Since the execution is asyncronious, you have to wait until is finish. You can just wait for some time in an old fashion way
your_code
wait(1000)
check results.
Or if you use Observables you can use TestSubscriber
In this example you can see how having an async operation we wait until the observer consume all items.
#Test
public void testObservableAsync() throws InterruptedException {
Subscription subscription = Observable.from(numbers)
.doOnNext(increaseTotalItemsEmitted())
.subscribeOn(Schedulers.newThread())
.subscribe(number -> System.out.println("Items emitted:" + total));
System.out.println("I finish before the observable finish. Items emitted:" + total);
new TestSubscriber((Observer) subscription)
.awaitTerminalEvent(100, TimeUnit.MILLISECONDS);
}
You can see more Asynchronous examples here https://github.com/politrons/reactive/blob/master/src/test/java/rx/observables/scheduler/ObservableAsynchronous.java

RxJava: How to get all results AND errors from an Observable

I'm working on a project that involves Hystrix, and I decided to use RxJava. Now, forget Hystrix for the rest of this because I believe the main problem is with my complete screwing up of writing the Observable code correctly.
Need:
I need a way to return an observable that represents a number of observables, each running a user task. I want that Observable to be able to return all results from the tasks, even errors.
Problem:
Observable streams die on errors. If I have three tasks and the second task throws an exception, I never receive the third task even if it would have succeeded.
My Code:
public <T> Observable<T> observeManagedAsync(String groupName,List<EspTask<T>> tasks) {
return Observable
.from(tasks)
.flatMap(task -> {
try {
return new MyCommand(task.getTaskId(),groupName,task).toObservable().subscribeOn(this.schedulerFactory.get(groupName));
} catch(Exception ex) {
return Observable.error(ex);
}
});
}
Given that MyCommand is a class that extends HystrixObservableCommand, it returns an Observable and so shouldn't figure in on the problems I'm seeing.
Attempt 1:
Used Observable.flatMap as above
Good: Each Command is scheduled on it's own thread and the tasks run asynchronously.
Bad: On first Command exception, Observable completes having emitted previous successful results and emitting the Exception. Any in-flight Commands are ignored.
Attempt 2:
Used Observable.concatMapDelayError instead of flatMap
Bad: For some reason, tasks run synchronously. Why??
Good: I get all the successful results.
~Good: OnError gets a Composite exception with a list of the exceptions thrown.
Any help will be greatly appreciated and probably result in me being very embarrassed for not having thought of it myself.
Additional Code
This test succeeds with Observable.flatMap, but fails when using Observable.concatMapDelayError because the tasks do not run asynchronously:
java.lang.AssertionError: Execution time ran over the 350ms limit: 608
#Test
public void shouldRunManagedAsyncTasksConcurrently() throws Exception {
Observable<String> testObserver = executor.observeManagedAsync("asyncThreadPool",getTimedTasks());
TestSubscriber<String> testSubscriber = new TestSubscriber<>();
long startTime = System.currentTimeMillis();
testObserver.doOnError(throwable -> {
System.out.println("error: " + throwable.getMessage());
}).subscribe(testSubscriber);
System.out.println("Test execution time: "+(System.currentTimeMillis()-startTime));
testSubscriber.awaitTerminalEvent();
long execTime = (System.currentTimeMillis()-startTime);
System.out.println("Test execution time: "+execTime);
testSubscriber.assertCompleted();
System.out.println("Errors: "+testSubscriber.getOnErrorEvents());
System.out.println("Results: "+testSubscriber.getOnNextEvents());
testSubscriber.assertNoErrors();
assertTrue("Execution time ran under the 300ms limit: "+execTime,execTime>=300);
assertTrue("Execution time ran over the 350ms limit: "+execTime,execTime<=350);
testSubscriber.assertValueCount(3);
assertThat(testSubscriber.getOnNextEvents(),containsInAnyOrder("hello","wait","world"));
verify(this.mockSchedulerFactory, times(3)).get("asyncThreadPool");
}
Tasks for the above unit test:
protected List<EspTask<String>> getTimedTasks() {
EspTask longTask = new EspTask("helloTask") {
#Override
public Object doCall() throws Exception {
Thread.currentThread().sleep(100);
return "hello";
}
};
EspTask longerTask = new EspTask("waitTask") {
#Override
public Object doCall() throws Exception {
Thread.currentThread().sleep(150);
return "wait";
}
};
EspTask longestTask = new EspTask("worldTask") {
#Override
public Object doCall() throws Exception {
Thread.currentThread().sleep(300);
return "world";
}
};
return Arrays.asList(longTask, longerTask, longestTask);
}
You can use Observable.onErrorReturn(), and return special value (e.g. null), then filter non-special values downstream. Keep in mind that source observable will complete on error. Also depending on use case Observable.onErrorResumeNext()methods can be useful aswell. If you are interested in error notifications, use Observable.materialize(), this will convert items and onError(), onComplete() into Notifications, which then can be filtered by Notification.getKind()
Edit.
All operators mentioned above should be added right after .toObservable().subscribeOn(this.schedulerFactory.get(groupName)); assuming try/catch was absent.
You want to use mergeDelayError:
public <T> Observable<T> observeManagedAsync(String groupName,List<EspTask<T>> tasks) {
return Observable.mergeDelayError(Observable
.from(tasks)
.map(task -> {
try {
return new MyCommand(task.getTaskId(),groupName,task).toObservable().subscribeOn(this.schedulerFactory.get(groupName));
} catch(Exception ex) {
return Observable.error(ex);
}
}));
}
Note that your MyCommand constructor should not throw any exceptions; this allows your code to be written more concisely:
public <T> Observable<T> observeManagedAsync(String groupName,List<EspTask<T>> tasks) {
return from(tasks)
.map(task -> new MyCommand(task.getTaskId(), groupName, task)
.toObservable()
.subscribeOn(this.schedulerFactory.get(groupName)))
.compose(Observable::mergeDelayError);
}
Keep in mind that this will still invoke onError at most once; if you need explicit handling of all errors, use something like an Either<CommandResult, Throwable> as the return type (or handle the errors and return an empty observable).
Use .materialize() to allow all emissions and errors to come through as wrapped notifications then deal with them as you wish:
.flatMap(task -> {
try {
return new MyCommand(task.getTaskId(),groupName,task)
.toObservable()
.subscribeOn(this.schedulerFactory.get(groupName))
.materialize();
} catch(Exception ex) {
return Observable.error(ex).materialize();
}
});

Categories