Java Reactor inapporiate blocking method inside Mono flatMap method - project-reactor

This part of code inside mono.flatMap(() -> ()) is giving me an error(or warning?) verifyClient.sms(request.phoneNumber(). Error is "Inappropriate blocking method call". I guess SMS call is a blocking call from a third party(TeleSign) sdk.
Error is shown in the picture.
#Override
public Mono<ResponseEntity<SuccessResponse>> postSms(
Mono<SendSmsDetail> sendSmsDetail, ServerWebExchange exchange) {
return sendSmsDetail.doOnNext(this::validate)
.flatMap(request -> {
try {
return Mono.just(verifyClient.sms(request.phoneNumber(),
buildSmsParam(request)));
} catch (Exception e) {
return Mono.error(new RuntimeException("Fail to verify", e));
}
})
.onErrorResume(this::defaultOrderErrorHandler);
}
Screenshot of the error:
Can someone please tell me how to resolve it? Just started using Reactor. By the way, if you notice the screenshot and the actual pasted code has differences on .flatMap(tlr -> tlr.) part. Code currently won't compile due to different return type. I am also trying to make it compile by returning Mono<ResponseEntity<SuccessResponse>>. That's what I am trying to do with the second flatMap. Change "tlr"(TeleSignResponse) to my own "SuccessResponse".
I may need a second post on how to make this compile.

Related

Sharing Mono with the publish method doesn't work as expected

I have two service calls. The second one accepts a value that the first returns. I need to return the result of the first call only if the second succeeds. The following is my prototype implementation, however, the resulting mono is always empty. Please explain why it doesn't work and how to implement it the proper way.
#Test
public void testPublish() {
callToService1().publish(
mono -> mono.flatMap(resultOfCall1 -> callToService2(resultOfCall1))
.then(mono)
)
.map(Integer::valueOf)
.as(StepVerifier::create)
.expectNext(1)
.verifyComplete();
}
Mono<String> callToService1() {
return Mono.just("1");
}
Mono<Integer> callToService2(String value) {
// parameter that used in a call to service2
return Mono.empty();
}
Not sure why you used publish(Function). Sounds like your requirement would be fulfilled by a simple direct flatMap:
callToService1()
.flatMap(v1 -> callToService2(v1)
.thenReturn(v1)
);
if callToService2 throws or produces an onError, that error will be propagated to the main sequence, terminating it.
(edited below for requirement of emitting value from service1)
otherwise, inside the flatMap the callToService2 is completed then we ignore the result and emit the still in scope v1 value thanks to thenReturn (which also propagates onError if callToService2 emits onError)

PromiseKit `Result.. is unused warning` in a chained sequence with a for loop

I have this annoying warning and I'm not able to get rid of it.
Let's say that I have a promise that sends a command to a bluetooth le device, to do a procedure I need to send these commands synchronously.
So what you can do in PromiseKit 6 is create a for loop and append each command using a then to the previous promise. The issue with that approach is that the compiler trigger a warning about an Result of call to 'then(on:flags:_:)' is unused, is like is missing the catch. I'm aware that I can use a cauterize() , but in this case I guess I will lost errors thrown while executing each promise. A when is not viable because it will execute concurrently while I need synchronously.
Here a small sample used with strings, in my real application they are NOT string.
static func promise_startProcedure(with commands: [String]) -> Promise<Void> {
let promise = Promise()
for command in commands {
promise.then { //<-- WARNING SHOW HERE
Promise.value(command)
}
}
return promise
}
Is there a way to get rid of this warning?
[UPDATE]
I did a mistake, the answer was not correct bu pointed me to the right direction.
static func promise_startProcedure(with commands: [String]) -> Promise<Void> {
var promise = Promise()
for command in commands {
promise = promise.then {
Promise.value(command)
}
}
return promise
}
Try this. I just added Underscore to suppress the warning and did not get that warning.
static func promise_startProcedure(with commands: [String]) -> Promise<Void> {
let promise = Promise()
for command in commands {
_ = promise.then {
Promise.value(command)
}
}
return promise
}
You can add #discardableResult to the declaration of the method. From the docs:
For example, the discardableResult attribute on a function declaration
indicates that, although the function returns a value, the compiler
shouldn’t generate a warning if the return value is unused.

"Operator called default onErrorDropped" on Mono timeout

In my Production code, I am getting errors in my logs when a Mono times out.
I have managed to recreate these errors with the following code:
#Test
public void testScheduler() {
Mono<String> callableMethod1 = callableMethod();
callableMethod1.block();
Mono<String> callableMethod2 = callableMethod();
callableMethod2.block();
}
private Mono<String> callableMethod() {
return Mono.fromCallable(() -> {
Thread.sleep(60);
return "Success";
})
.subscribeOn(Schedulers.elastic())
.timeout(Duration.ofMillis(50))
.onErrorResume(throwable -> Mono.just("Timeout"));
}
In the Mono.fromCallable I am making a blocking call using a third-party library. When this call times out, I get errors similar to
reactor.core.publisher.Operators - Operator called default onErrorDropped
reactor.core.publisher.Operators - Scheduler worker in group main failed with an uncaught exception
These errors also seem to be intermittent, sometimes when I run the code provided I get no errors at all. However when I repeat the call in a loop of say 10, I consistently get them.
Question: Why does this error happen?
Answer:
When the duration given to the timeout() operator has passed, it throws a TimeoutException. That results in the following outcomes:
An onError signal is sent to the main reactive chain. As a result, the main execution is resumed and the process moves on (i.e., onErrorResume() is executed).
Shortly after outcome #1, the async task defined within fromCallable() is interrupted, which triggers a 2nd exception (InterruptedException). The main reactive chain can no longer handle this InterruptedException because the TimeoutException happened first and already caused the main reactive chain to resume (Note: this behavior of not generating a 2nd onError signal conforms with the Reactive Stream Specification -> Publisher #7).
Since the 2nd exception (InterruptedException) can't be handled gracefully by the main chain, Reactor logs it at error level to let us know an unexpected exception occurred.
Question: How do I get rid of them?
Short Answer: Use Hooks.onErrorDropped() to change the log level:
Logger logger = Logger.getLogger(this.getClass().getName());
#Test
public void test() {
Hooks.onErrorDropped(error -> {
logger.log(Level.WARNING, "Exception happened:", error);
});
Mono.fromCallable(() -> {
Thread.sleep(60);
return "Success";
})
.subscribeOn(Schedulers.elastic())
.timeout(Duration.ofMillis(50))
.onErrorResume(throwable -> Mono.just("Timeout"))
.doOnSuccess(result -> logger.info("Result: " + result))
.block();
}
Long Answer: If your use-case allows, you could handle the exception happening within fromCallable() so that the only exception affecting the main chain is the TimeoutException. In that case, the onErrorDropped() wouldn't happen in the first place.
#Test
public void test() {
Mono.fromCallable(() -> {
try {
Thread.sleep(60);
} catch (InterruptedException ex) {
//release resources, rollback actions, etc
logger.log(Level.WARNING, "Something went wrong...", ex);
}
return "Success";
})
.subscribeOn(Schedulers.elastic())
.timeout(Duration.ofMillis(50))
.onErrorResume(throwable -> Mono.just("Timeout"))
.doOnSuccess(result -> logger.info("Result: " + result))
.block();
}
Extra References:
https://tacogrammer.com/onerrordropped-explained/
https://medium.com/#kalpads/configuring-timeouts-in-spring-reactive-webclient-4bc5faf56411

env->ExceptionCheck() in JNA

I am using JNA in my project and my Java JNA Callbacks throw exception in some cases. I want to know from C/C++ code an exception was thrown by last calbback method call. In JNI, one can do it using env->ExceptionCheck() but could not find any equivalent in JNA.
Is there any possibility to achieve this?
The native code calling your callback certainly has no expectation that a Java exception will be raised. There is no guarantee that a JNA callback will be invoked from a containing JVM context. Even if it were, you'd have to establish an out of band channel to pass the exception from the callback to the JVM further up the stack, since you have no guarantees about the calling C code.
Assuming you have Java code -> C code -> callback, I'd recommend you catch all your callback's exceptions, then put them somewhere for the calling Java code to examine after the call.
You could make this happen under the covers with an InvocationMapper, which basically lets you capture and/or modify the results of an interface-mapped call, but it's probably easier just to be explicit about it and wrap the whole thing in a utility function.
For example:
public interface MyLibrary extends Library {
MyLibrary INSTANCE = (MyLibrary)Native.loadLibrary();
interface MyCallback extends Callback {
void invoke();
}
void myFunction(MyCallback callback);
}
Then you provide a utility wrapper:
public void myFunction(final MyCallback callback) {
final List<Exception> exceptions = new List<Exception>();
MyLibrary.INSTANCE.myFunction(new MyCallback() {
public void invoke() {
try {
callback.invoke();
} catch(Exception e) {
exceptions.add(e);
}
}
});
if (exceptions.size() > 0) {
// ...
}
}

When to use Future.handleexception in Dart and when to try-catch

I'm trying to really get Futures in Dart and I've noticed that just about every example I come across uses handleException to deal with exceptions that complete the Future. Yet the API documentation states "In most cases it should not be necessary to call handleException, because the exception associated with this Future will propagate naturally if the future's value is being consumed. Only call handleException if you need to do some special local exception handling related to this particular Future's value."
So when would I need "special local exception handling"? Could someone explain that in a bit more detail? Is there some code that I honestly can't run easily by letting the exception propagate?
Mads Ager gave me this answer:
Basically, this is the equivalent of having a try-catch in straight-line code:
int doSomethingElse() {
try {
return thisMightFail();
} catch(e) {
return -1;
}
}
void doSomething() {
int value = doSomethingElse();
// operate on value
}
With Futures it is something like this (not tested):
Future<int> doSomethingElse() {
return thisMightFail().transformException((e) => -1);
}
void doSomething() {
doSomethingElse().then((value) {
// operate on value
});
}
So this is for local exception handling instead of global exception handling. If you never use handleException or transformException that would correspond to always dealing with exceptions at the top level in non-async code.

Resources