RxJava2 - no event received with .blockingFirst() - java

I'm trying to get a value from my Observable (BehaviorSubject.create())
When I run locationObservable.subscribe {} I receive the results withing a few seconds. However with
try {
it.locationObservable
.timeout(10, TimeUnit.SECONDS)
.blockingFirst()
} catch (e: Exception) {
}
nothing happens with or without timeout. I simply receive "java.util.concurrent.TimeoutException: The source did not signal an event for 10 seconds and has been terminated". I have tried blockingFirst(), blockingLast() and blockingForEach(). Am I somehow blocking the thread that would provide me with the value?
EDIT: After moving it from the main thread it started working. Thank you everyone for your input.

The operator .observeOn(Schedulers.io()) will queue all emitted items to be emitted in the IO thread of the Android application.

Try the following:
.timeout(10, TimeUnit.SECONDS, Observable.just("fallback"))

Related

How to use main thread when delayElement is used in reactor Publisher

How to use main thread when delayElement is used in reactor Publisher.
Mono.just("one")
.delayElement(Duration.ofSeconds(3))
.subscribe(System.out::println);
If I run this code, it will not print "one", because main thread will exit and subscription is done on other thread.
Is there a way to use main thread for subscription of this Mono when I use delayElement?
i.e. wait until "one" is published down the line after 3 seconds, and until subscriber consume it.
Please mind that if I would not have used "delayElement", I could have blocked main thread until it print "one" on screen.
Mono.just("one")
.subscribe(System.out::println);
I am aware that I can achieve similar output by using wait and notify (or similar alternative), but what I want is, to use main thread for subscribing element after delayElement is called.
Mono class used is imported from reactor.core.publisher.Mono
Consider below example, in which I will use same thread for delay operation of my own implementation.
Mono.just("one")
.doOnNext(a -> this.myDelayOperation(Duration.ofSeconds(1)))
.subscribe(System.out::println);
where myDelayOperation(...) is
private void myDelayOperation(Duration duration) {
try {
Thread.sleep(duration.toMillis());
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}

How to wait for WebClient response on timeout in Spring?

I have a WebClient that I want to stop and provide a fallback value after a certain timeout.
webClient.post()
.uri(path)
.bodyValue(body)
.retrieve()
.bodyToMono(type)
.timeout(Duration.ofSeconds(15))
.onErrorResume(ex -> Mono.just(provideFallbackValue())); //not only timeout, but any failure
Anyways, I would like to continue waiting for the response in another background thread in case of a TimeoutException (at least for let's say for another 60s), and still process the response then async.
Is that possible?
What you can do is change the point of view of this code. Instead of wait for additional 60 seconds in another thread start immediately the new thread and work asynchronously.
If the answer from the second thread arrives in 15 seconds or less you can reply immediately. Otherwise, send the message related to the error, but you still have active the call until 60 seconds.
Here is a code that can do that:
private Future<YourClass> asyncCall() {
...
// Put here the async call with a timeout of 60 seconds
// This call can be sync because you are already in a secondary thread
}
// Main thread
try {
Future<YourClass> future = executors.submit(() -> asyncCall());
YourClass result = future.get(15, TimeUnit.SECOND);
// Result received in less than 15 seconds
} catch (TimeoutException e) {
// Handle timeout of 15 seconds
}

Flux behaving differently for Webclient vs simple Flux.just

I have basic rest controller in Spring.To try out spring webflux and understand its non blocking nature.I created two controller mappings one to read and and one to serve the webclient call(as shown below)
#GetMapping("/slow-service-tweets")
private List<String> getAllTweets() {
try {
Thread.sleep(2000L); // delay
} catch (InterruptedException e) {
e.printStackTrace();
}
return Arrays.asList(
"Item1", "Item2","Item3");
}
And here is my testing get api which just triggers the code given below(first version)
#GetMapping("/test")
public void doSomething(){
log.info("Starting NON-BLOCKING Controller!");
Flux<String> tweetFlux = WebClient.create()
.get()
.uri("http://localhost:9090/slow-service-tweets")
.retrieve()
.bodyToFlux(String.class);
tweetFlux.subscribe(tweet ->{
try {
log.info("i am back");
Thread.sleep(6000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.info(tweet.toString());});
log.info("Exiting NON-BLOCKING Controller!");
The above code behaves exactly as it should.The output is
Starting NON-BLOCKING Controller!
Exiting NON-BLOCKING Controller!
Item1
Item2
Item3
The reason being the thread does not block on subscribe of flux and proceeds ahead.
Now please look in the second version of this below.
#GetMapping("/test")
public void doSomething(){
System.out.println("i am here");
Flux<Integer> f= Flux.just(1,2,3,4,5);
// Flux<Integer> f= Flux.fromIterable(testService.returnStaticList());
f.subscribe(consumer->{
try {
log.info("consuming");
Thread.sleep(2000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.info(consumer);
});
log.info("doing something else");
}
Ideally like the earlier example
"doing something else" must be printed immediately.
But no matter what i do it takes 10 seconds to print all element and then prints "doing something else".Output below:
i am here
consuming
1
2
3
4
5
doing something else
Can anyone please explain what am i missing here??
I feel like I need to start with a warning - this is most certainly not how to use Webflux. Any time you call subscribe, you're almost certainly doing something wrong - that should be left to the framework. Instead, you should be using:
doOnNext() for side effects like logging;
delayElements() if you want to delay each element in a Flux, rather than using Thread.sleep();
Returning your Flux (or returning some publisher created by chaining your Flux using operators) from your doSomething() method, to allow the framework to subscribe and therefore execute your reactive chain.
If you follow the above "normal" way of doing things, you likely won't run into these sorts of problems with blocking / threading causing unexpected problems. If you do more niche things like subscribe yourself, block threads without thinking if they should be blocked, etc. - then you'll likely cause yourself a world of issues.
However, to answer the question directly as to why this behaviour happens - it's because of threading. When you use Flux.just(), you're using the immediate scheduler (which means the same thread that's actually executing your doSomething() method in the first place.) Since there's only one thread at play here, your subscribe method blocks this one thread it until it's complete, so nothing else can execute. If you were to tell your Flux to publish on the boundedElastic() thread pool for instance like so, you'd find it behaves as you expect:
Flux<Integer> f = Flux.just(1, 2, 3, 4, 5).subscribeOn(Schedulers.boundedElastic());
In your other example, when you use WebClient, it's publishing on a different thread to the one executing your method - so blocking this different thread in a subscriber doesn't hold up the overall executing of your doSomething() method.

Java - proper cancel execution of thread after TimeoutException

I have a java-program which runs on a schedule and fetches some data from external sources via RFC calls. The RFC calls are threaded and shall be canceled after 60 seconds. This is how I do it:
Future<String> future = executor.submit(new MyCallable());
try {
future.get(60, TimeUnit.SECONDS);
} catch (TimeoutException e) {
future.cancel(true);
}
This worked for a long time until I came accross a situation, where the external RFC call became stuck and future.cancel(true) was unable to interrupt the thread-execution. So my java-program never finished and continued running until I manually canceled the corresponding process within the external system.
My question now is, how can one guarantee the code to finish in any situation? I saw that stopping the thread is depreciated.
Would it be a good idea to do sth like this?
try {
future.get(60, TimeUnit.SECONDS);
} catch (TimeoutException e) {
future.cancel(true);
if(!future.isDone()){
System.exit(1);
}
}
Thanks for any ideas on this.
Cheers, Jooo
I believe that there's no way in Java to just kill off a thread if during execution not implemented InterruptedException . If the thread is executing, it just sets a flag and it's up to the thread to notice it. if the thread is waiting or sleeping, it will throw an InterruptedException.
No need to check after every line, of course, but methods which can take a long time to execute are responsible for properly handling interrupts
kill the process in which the thread is running. (E.g., call System.exit(int).)

How to interrupt a function call in Java

I am trying to use a Third Party Internal Library which is processing a given request. Unfortunately it is synchronous in nature. Also I have no control on the code for the same. Basically it is a function call. This function seems to a bit erratic in behavior. Sometimes this function takes 10 ms to complete processing and sometimes it takes up to 300 secs to process the request.
Can you suggest me a way to write a wrapper around this function so that it would throw an interrupted exception if the function does not complete processing with x ms/secs. I can live with not having the results and continue processing, but cannot tolerate a 3 min delay.
PS: This function internally sends an update to another system using JMS and waits for that system to respond and sends apart from some other calculations.
Can you suggest me a way to write a wrapper around this function so that it would throw an interrupted exception if the function does not complete processing with x ms/secs.
This is not possible. InterruptException only gets thrown by specific methods. You can certainly call thread.stop() but this is deprecated and not recommended for a number of reasons.
A better alternative would be for your code to wait for the response for a certain amount of time and just abandon the call if doesn't work. For example, you could submit a Callable to a thread pool that actually makes the call to the "Third Party Internal Library". Then your main code would do a future.get(...) with a specific timeout.
// allows 5 JMS calls concurrently, change as necessary or used newCachedThreadPool()
ExecutorService threadPool = Executors.newFixedThreadPool(5);
...
// submit the call to be made in the background by thread-pool
Future<Response> future = threadPool.submit(new Callable<Response>() {
public Response call() {
// this damn call can take 3 to 3000ms to complete dammit
return thirdPartyInternalLibrary.makeJmsRequest();
}
});
// wait for some max amount of time
Response response = null;
try {
response = future.get(TimeUnit.MILLISECONDS, 100);
} catch (TimeoutException te) {
// log that it timed out and continue or throw an exception
}
The problem with this method is that you might spawn a whole bunch of threads waiting for the library to respond to the remote JMS query that you would not have a lot of control over.
No easy solution.
This will throw a TimeoutException if the lambda doesn't finish in the time allotted:
CompletableFuture.supplyAsync(() -> yourCall()).get(1, TimeUnit.SECONDS)
Being that this is 3rd party you cannot modify the code. As such you will need to do two things
Launch the execution in a new thread.
Wait for execution in current thread, with timeout.
One possible way would be to use a Semaphore.
final Semaphore semaphore = new Semaphore(0);
Thread t = new Thread(new Runnable() {
#Override
public void run() {
// do work
semaphore.release();
}
});
t.start();
try {
semaphore.tryAcquire(1, TimeUnit.SECONDS); // Whatever your timeout is
} catch (InterruptedException e) {
// handle cleanup
}
The above method is gross, I would suggest instead updateing your desing to use a dedicated worker queue or RxJava with a timeout if possible.

Categories

Resources