Writing imperative code in Project Reactor - spring

I have a class with the following two methods.
public class Test1 {
public Mono<String> blah1() {
Mono<String> blah = Mono.just("blah1");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("blah1 done");
return blah;
}
public Mono<String> blah2() {
Mono<String> blah = Mono.just("blah2");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("blah2 done");
return blah;
}
}
I have the following JUnit:
#Test
public void blah1Test() {
Flux<Tuple2<String, String>> s = Flux.zip(test1.blah1(), test1.blah2());
}
My result is as follows:
blah1 done
blah2 done
I expect blah2 to finish before blah1. Thus I believe this is processing blocking instead of non blocking. What do I need to do to have the output switch to blah2 done then blah1 done? Basically why are these not processing in parallel?
Thanks in advance for your time!

Both sleep and println are executed outside the reactive pipeline. Therefore, both blah1() and blah2() behave like regular, non-reactive methods.
Try this:
public Mono<String> blah1() {
System.out.println("blah1 start");
return Mono.just("blah1")
.delayElement(Duration.ofMillis(5000))
.doOnNext(e -> System.out.println("blah1 done"));
}
public Mono<String> blah2() {
System.out.println("blah2 start");
return Mono.just("blah2")
.delayElement(Duration.ofMillis(1000))
.doOnNext(e -> System.out.println("blah2 done"));
}
Here, we have the expected result because printing takes place within the reactive pipeline.
Output:
blah1 start
blah2 start
blah2 done
blah1 done

Related

Parameterize Test in SpringBoot

I have an ExceptionTest class where I store the Tests for each of the classes. I have quite a few methods where I am repeating the same structure.
public class ExceptionTest {
#Test
void conversionException() {
assertThrows(ConversionException.class, () -> {
try {
throw new ConversionException();
} catch (QOException ex) {
assertEquals("Error converting", ex.getMessage());
assertEquals(417 /* FAILED */, ex.getHttpStatus());
assertEquals(ErrorCodes.DOCUMENT_ERROR, ex.getCode());
throw ex;
}
});
}
#Test
void userException() {
assertThrows(UserException.class, () -> {
try {
Integer maxUsers = 5;
throw new UserException(maxUsers);
} catch (QOException ex) {
Integer maxUsers = 5;
assertEquals("Excedido "+ maxUsers +" disp", ex.getMessage());
assertEquals(403 /* FORBIDDEN */, ex.getHttpStatus());
assertEquals(ErrorCodes.USERS, ex.getCode());
throw ex;
}
});
}
}
From what I have read in Spring you can use the #ParameterizedTest annotation in a separate class and call that class from each Test method, and collect it from the method parameterized with the #MethodSource annotation.
This is the code I am looking for:
#ParameterizedTest
#MethodSource("stringProvider")
void testWithExplicitLocalMethodSource(String argument) {
assertNotNull(argument);
}
The problem is that I do not apply it to the classes I have in Test. How do I have to create the method in a separate class to apply the structure to all the Tests that are in the ExceptionTest class?
Your question seems familiar to an article posted by Baeldung.com; where they gave this as example:
class StringsUnitTest {
#ParameterizedTest
#MethodSource("com.baeldung.parameterized.StringParams#blankStrings")
void isBlank_ShouldReturnTrueForNullOrBlankStringsExternalSource(String input) {
assertTrue(Strings.isBlank(input));
}
}
public class StringParams {
static Stream<String> blankStrings() {
return Stream.of(null, "", " ");
}
}

Get queue size of ThreadPoolTaskExecutor and add to queue in Spring boot

I have the following class which has multiple custom ThreadPoolTaskExecutors I am showing it with one in this example.
#Configuration
#EnableAsync
public class ExecutorConfig {
#Bean(name = "streetCheckerExecutor")
public Executor getStreetAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(50);
executor.setQueueCapacity(1000000);
executor.setThreadNamePrefix("streetCheckerExecutor-");
executor.initialize();
return executor;
}
}
I have the following class which gets content from the database, I want to be able to check the queue size of streetCheckerExecutor and if it's less than a certain number, to add the content to the queue
#Component
public class StreetChecker {
#Autowired
StreetRepository streetRepository;
#Autowired
StreetCheckService streetChecker;
#EventListener(ApplicationReadyEvent.class)
public void checkStreets() {
try {
List<Street> streetList = streetRepository.getStreets();
for (int i = 0; i < streetList.size(); i++) {
streetChecker.run(streetList.get(i));
}
} catch (Exception e) {
e.printStackTrace();
} finally {
System.out.println("---------------------");
}
}
}
And below is the worker class
#Component
public class StreetCheckService {
#Async("streetCheckerExecutor")
public void run(Content content) {
try {
//do work
} catch (Exception e) {
e.printStackTrace();
} finally {
}
}
}
I am working with a lot of data and I don't want to grab everything from the database every time, but I want to check the queue size of streetCheckerExecutor and if it's less than a number, I want to get more content from the database and add it to the streetCheckerExecutor queque
Below is how I'm thinking I can do it by converting the above checkStreets to the one below
#EventListener(ApplicationReadyEvent.class)
public void checkStreets() {
while (true) {
try {
// check the queue size of streetCheckerExecutor
// if less than a number
// add to the queue
// else keep waiting and will try again in X minutes
} catch (Exception e) {
} finally {
try {
Thread.sleep(1000 * 60);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
But how would I be able to get the size of the queue in the checkStreets() method?
You can just autowire in your ThreadPoolTaskExecutor and get the queue with getThreadPoolExecutor().getQueue().
#Autowire
#Qualifier("streetCheckerExecutor")
private Executor streetExecutor;
#EventListener(ApplicationReadyEvent.class)
public void checkStreets() {
while (true) {
try {
final BlockingQueue<Runnable> queue = streetExecutor.getThreadPoolExecutor().getQueue();
if(queue.size() <= 5) {
queue.add(() -> {
final List<Street> streetList = streetRepository.getStreets();
streetList.forEach(street -> {
streetChecker.run(street);
});
});
}
} catch (Exception e) {
} finally {
try {
Thread.sleep(1000 * 60);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
i'm not sure this is what you meant, but something like this maybe.

Spring Integration Reactor configuration

I'm running an application that process tasks using spring integration.
I'd like to make it process multiple tasks concurrently but any attempt failed so far.
My configuration is:
ReactorConfiguration.java
#Configuration
#EnableAutoConfiguration
public class ReactorConfiguration {
#Bean
Environment reactorEnv() {
return new Environment();
}
#Bean
Reactor createReactor(Environment env) {
return Reactors.reactor()
.env(env)
.dispatcher(Environment.THREAD_POOL)
.get();
}
}
TaskProcessor.java
#MessagingGateway(reactorEnvironment = "reactorEnv")
public interface TaskProcessor {
#Gateway(requestChannel = "routeTaskByType", replyChannel = "")
Promise<Result> processTask(Task task);
}
IntegrationConfiguration.java (simplified)
#Bean
public IntegrationFlow routeFlow() {
return IntegrationFlows.from(MessageChannels.executor("routeTaskByType", Executors.newFixedThreadPool(10)))
.handle(Task.class, (payload, headers) -> {
logger.info("Task submitted!" + payload);
payload.setRunning(true);
//Try-catch
Thread.sleep(999999);
return payload;
})
.route(/*...*/)
.get();
}
My testing code can be simplified like this:
Task task1 = new Task();
Task task2 = new Task();
Promise<Result> resultPromise1 = taskProcessor.processTask(task1).flush();
Promise<Result> resultPromise2 = taskProcessor.processTask(task2).flush();
while( !task1.isRunning() || !task2.isRunning() ){
logger.info("Task2: {}, Task2: {}", task1, task2);
Thread.sleep(1000);
}
logger.info("Yes! your tasks are running in parallel!");
But unfortunately, the last log line, will never get executed!
Any ideas?
Thanks a lot
Well, I've reproduced it just with simple Reactor test-case:
#Test
public void testParallelPromises() throws InterruptedException {
Environment environment = new Environment();
final AtomicBoolean first = new AtomicBoolean(true);
for (int i = 0; i < 10; i++) {
final Promise<String> promise = Promises.task(environment, () -> {
if (!first.getAndSet(false)) {
try {
Thread.sleep(1000);
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
return "foo";
}
);
String result = promise.await(10, TimeUnit.SECONDS);
System.out.println(result);
assertNotNull(result);
}
}
(It is with Reactor-2.0.6).
The problem is because of:
public static <T> Promise<T> task(Environment env, Supplier<T> supplier) {
return task(env, env.getDefaultDispatcher(), supplier);
}
where DefaultDispatcher is RingBufferDispatcher extends SingleThreadDispatcher.
Since the #MessagingGateway is based on the request/reply scenario, we are waiting for reply within that RingBufferDispatcher's Thread. Since you don't return reply there (Thread.sleep(999999);), we aren't able to accept the next event within RingBuffer.
Your dispatcher(Environment.THREAD_POOL) doesn't help here because it doesn't affect the Environment. You should consider to use reactor.dispatchers.default = threadPoolExecutor property. Something like this file: https://github.com/reactor/reactor/blob/2.0.x/reactor-net/src/test/resources/META-INF/reactor/reactor-environment.properties#L46.
And yes: upgrade, please, to the latest Reactor.

RxJava cache last item for future subscribers

I have implemented simple RxEventBus which starts emitting events, even if there is no subscribers. I want to cache last emitted event, so that if first/next subscriber subscribes, it receive only one (last) item.
I created test class which describes my problem:
public class RxBus {
ApplicationsRxEventBus applicationsRxEventBus;
public RxBus() {
applicationsRxEventBus = new ApplicationsRxEventBus();
}
public static void main(String[] args) {
RxBus rxBus = new RxBus();
rxBus.start();
}
private void start() {
ExecutorService executorService = Executors.newScheduledThreadPool(2);
Runnable runnable0 = () -> {
while (true) {
long currentTime = System.currentTimeMillis();
System.out.println("emiting: " + currentTime);
applicationsRxEventBus.emit(new ApplicationsEvent(currentTime));
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
Runnable runnable1 = () -> applicationsRxEventBus
.getBus()
.subscribe(new Subscriber<ApplicationsEvent>() {
#Override
public void onCompleted() {
}
#Override
public void onError(Throwable throwable) {
}
#Override
public void onNext(ApplicationsEvent applicationsEvent) {
System.out.println("runnable 1: " + applicationsEvent.number);
}
});
Runnable runnable2 = () -> applicationsRxEventBus
.getBus()
.subscribe(new Subscriber<ApplicationsEvent>() {
#Override
public void onCompleted() {
}
#Override
public void onError(Throwable throwable) {
}
#Override
public void onNext(ApplicationsEvent applicationsEvent) {
System.out.println("runnable 2: " + applicationsEvent.number);
}
});
executorService.execute(runnable0);
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
executorService.execute(runnable1);
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
executorService.execute(runnable2);
}
private class ApplicationsRxEventBus {
private final Subject<ApplicationsEvent, ApplicationsEvent> mRxBus;
private final Observable<ApplicationsEvent> mBusObservable;
public ApplicationsRxEventBus() {
mRxBus = new SerializedSubject<>(BehaviorSubject.<ApplicationsEvent>create());
mBusObservable = mRxBus.cache();
}
public void emit(ApplicationsEvent event) {
mRxBus.onNext(event);
}
public Observable<ApplicationsEvent> getBus() {
return mBusObservable;
}
}
private class ApplicationsEvent {
long number;
public ApplicationsEvent(long number) {
this.number = number;
}
}
}
runnable0 is emitting events even if there is no subscribers. runnable1 subscribes after 3 sec, and receives last item (and this is ok). But runnable2 subscribes after 3 sec after runnable1, and receives all items, which runnable1 received. I only need last item to be received for runnable2. I have tried cache events in RxBus:
private class ApplicationsRxEventBus {
private final Subject<ApplicationsEvent, ApplicationsEvent> mRxBus;
private final Observable<ApplicationsEvent> mBusObservable;
private ApplicationsEvent event;
public ApplicationsRxEventBus() {
mRxBus = new SerializedSubject<>(BehaviorSubject.<ApplicationsEvent>create());
mBusObservable = mRxBus;
}
public void emit(ApplicationsEvent event) {
this.event = event;
mRxBus.onNext(event);
}
public Observable<ApplicationsEvent> getBus() {
return mBusObservable.doOnSubscribe(() -> emit(event));
}
}
But problem is, that when runnable2 subscribes, runnable1 receives event twice:
emiting: 1447183225122
runnable 1: 1447183225122
runnable 1: 1447183225122
runnable 2: 1447183225122
emiting: 1447183225627
runnable 1: 1447183225627
runnable 2: 1447183225627
I am sure, that there is RxJava operator for this. How to achieve this?
Your ApplicationsRxEventBus does extra work by reemitting a stored event whenever one Subscribes in addition to all the cached events.
You only need a single BehaviorSubject + toSerialized as it will hold onto the very last event and re-emit it to Subscribers by itself.
You are using the wrong interface. When you susbscribe to a cold Observable you get all of its events. You need to turn it into hot Observable first. This is done by creating a ConnectableObservable from your Observable using its publish method. Your Observers then call connect to start receiving events.
You can also read more about in the Hot and Cold observables section of the tutorial.

Android calling AsyncTask().get() without execute()?

I'm having issues trying to understand how AsyncTask().get() actually works. I know it's a synchronous execution, However: I don't know how execute() and get() are connected.
I have this sample code from Google's docs:
// Async Task Class
class DownloadMusicfromInternet extends AsyncTask<String, String, String> {
// Show Progress bar before downloading Music
#Override
protected void onPreExecute() {
super.onPreExecute();
Log.d("Task: ", "onPreExecute()");
}
// Download Music File from Internet
#Override
protected String doInBackground(String... f_url) {
for (int i = 0; i < 100; i++){
try {
Thread.sleep(100);
Log.d("Task: ", String.valueOf(i));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return null;
}
// While Downloading Music File
protected void onProgressUpdate(String... progress) {
// Set progress percentage
Log.d("Task: ", "onProgressUpdate()");
}
// Once Music File is downloaded
#Override
protected void onPostExecute(String file_url) {
Log.d("Task: ", "onPostExecute()");
}
}
Now, from a button.onClick() I call this in 3 ways:
new DownloadMusicfromInternet().execute("");//works as expected, the "normal" way
//works the normal way, but it's synchronous
try {
new DownloadMusicfromInternet().execute("").get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
//does not work
try {
new DownloadMusicfromInternet().get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
I'm confused as to how exactly execute() triggers doInBackground() and then immediately returns if get() is called, while get() has no effect on doInBackground() whatsoever.
execute() schedules the internal FutureTask (usually on a internal Executor) and returns immediately.
get() just calls FutureTask.get() on this internal future, i.e. it waits (if necessary) for the result.
So calling get() without calling execute() first waits indefinitely, as the result will never be available.
As you mentioned, when used the normal way, get() is not needed at all, as the result is handled in onPostExecute(). I didn't even know it existed before I tried to understand your question

Resources