RxJava2 Single does not handle error even if doOnerror is provided - rx-java2

I've encountered an issue using RxJava2 (version 2.2.2). See the code below:
client.get("/iic-router/health").rxSend()
.doOnError(err -> { err.printStackTrace(); async.complete(); })
.doOnSuccess(v -> async.complete())
.subscribe();
As you can see, the rxSend() method returns an instance of Single. When I run this code and the WebServer is not started I get an error of Connectiong Refused (as expected), but I get an error:
io.reactivex.exceptions.OnErrorNotImplementedException: The exception
was not handled due to missing onError handler in the subscribe() method call.
If I change the code for more traditional way on RxJava like this:
client.get("/iic-router/health").rxSend().subscribe(
v -> async.complete(),
err -> { err.printStackTrace(); async.complete(); }
);
Everything works well. Anyone can help me ? Or it's a real bug ?

This is not a bug and the simple subscribe() is documented:
Subscribes to a Single but ignore its emission or notification.
If the Single emits an error, it is wrapped into an OnErrorNotImplementedException and routed to the RxJavaPlugins.onError handler.
The OnErrorNotImplementedException said that you need to implement the onError Handler, like you did in your second example.
Instead of doOnError, you can also try onErrorResumeNext or onErrorReturn which won't invoke onError on subscribe.

Related

Vertx - Multiple failureHandlers for the same route

The question is simple: is it possible to have multiple failure handlers for one route?
router.route(HttpMethod.POST, "/test")
.handler(LoggerHandler.create())
.handler(ResponseTimeHandler.create())
.failureHandler(MyCustomFailureHandler1.create())
.failureHandler(MyCustomFailureHandler2.create());
I'm currently using vert.x version 4.0.2, and I can see that internally, every failure handler I create is added to a failureHandlers list, but when an error is thrown, the only failure handler executing is the first one specified.
From the first failure handler (MyCustomFailureHandler1.create()), you have to call RoutingContext#next()
Documentation of RoutingContext#next() states: "If next is not called for a handler then the handler should make sure it ends the response or no response will be sent".
See TestCase here: testMultipleSetFailureHandler

Is it a good pattern to subscribe a Mono before return it?

I want to subscribe a Mono before return it, the consumer of the subscriber will do some work like write some info, the code looks like this:
Mono result = a remote call by WebClient;
result.subscribe(data->successLog(log,JSON.toJSONString(data)));
return result;
and now the problem comes:
that remote call by WebClient will triggered twice!
how to subscribe a Mono and do something before return it?
It is not :)
In Reactive Streams, everything is "lazy" by default: you're not "calling operations" (imperative), you're building a pipeline that will later be executed (where subscribe() is what triggers the execution).
If you need to log when Mono successfully resolves, you can use Mono#doOnNext:
return result.doOnNext(data -> successLog(log, JSON.toJSONString(data)));
This way it will log every time your Mono is resolved.
Why "every time"? Because, in Reactive Streams, it is absolutely valid to re-subscribe on the same Mono (e.g. for retrying).

Reactive asynchronous feedback system with RxSwift

I am designing a call manager with the help of RXSwift (ReactiveX) that continuously interacts with an API. The call manager comprises several objects that itself comprises an indicator (indicating status information loaded from the API) and control (requests to be sent to the API).
class CallManagerObjectA() {
var control = PublishSubject<String>()
var indicator = BehaviorSubject<String>(value: "string status")
}
Within the call manager, a scheduler regularly provides new values to the indicator observable:
<... API response ...>
indicator.onNext(newValue)
Somewhere else in a view controller, the indicator will be observed for a label:
indicator.subscribe(onNext: { label.stringValue = $0 })
Within the same view controller, the user can control the object status via GUI elements continuously:
control.onNext(commandValue)
Within the call manager, the control will be observed for an API call:
control.subscribe(onNext: { (command) in
// API request call
})
So far so good, this is working very well with reactive patterns.
Now, I am looking for a good solution to handle errors, if the call manager recognizes errors during the API interaction and show these errors to the user in the view controller. I was immediately thinking of something like this:
// Call manager recognizes the error
control.onError(error)
...
// Call manager ignores errors for the subscriber
control.retry().ignoreErrors().subscribe(onNext: { (command) in
// API request call
})
...
// View controller shows the errors
indicator.subscribe(onNext: { label.stringValue = $0 })
control.subscribe(onError: { print("error", $0) })
This however ends up in an infinite loop.
I fear that I have a fundamental understanding issue with reactive programming, or I miss something very important, but I am not able to understand how the handle errors in this reactive pattern environment.
Based on the code you have shown, you have a big misunderstanding, not just with how to handle Errors, but with how to program reactively in general. Try watching this video "Reactive Programming: Why It Matters"
To answer your specific question, there are two misunderstandings here:
When you call control.onError(_:) it will be the last call you will be able to make on control. Once it emits an error it will stop working.
The retry() operator asks its source to "try again on Error". If it's source is determinate, then it will just do the exact same thing it did before and emit the exact same output (i.e., the same error it emitted last time.) In the case of a PublishSubject, it doesn't know why onError was called. So the best it can do is just emit the error again.
Honestly, I consider this a bug in the API because subscribing to a publish subject that emitted an error at some point in the past should just do nothing. But then, you wouldn't be asking why you got an infinite loop. Instead you would be asking why your control stopped emitting events.

Scalatra: printing the HTTP status code of all APIs

I have a scalatra servlet with multiple REST APIs. For logging purposes, I use the after() method to print out the return status code after each API is called.
after() {
logger.info("request {} {} returned with status code {}", request.getMethod, request.getRequestURL, response.getStatus.toString)
}
I have noticed that when a method returns with halt, the status code is printed correctly, but when the method return a status code in the last line (without halt), the status code which will be printed will always be 200, regardless of real status returned.
For example:
post("/users/:user") {
try {
//some logic here...
if(condition)
halt(InternalServerError("DB error")) //this will cause status 500 to be printed in the 'after' method
} catch {
case e: Exception =>
InternalServerError("an unknown error occurred") //this will cause status 200 to be printed in the 'after' method
}
}
The user gets back the real status code (500) in both cases.
Any idea why this happens? Is this a bug?
I posted this question on the scalatra-user mailing list, but the list seems to be quite inactive.
Aliza
(disclaimer: I'm not a Scalatra developer but I have been using it for a project. This is based on me reading the code some time ago.)
This has to do with the way Scalatra is handling thrown exceptions (the relevant code seems to be start from this one). If the somewhere in runActions an exception is thrown (halt throws a HaltException), the catch block of cradleHalt will be called and we go to renderHaltException which will set the response status code.
It's not exactly the same when you're not calling halt but returns an ActionResult directly. In that case, executeRoutes seems to produce a value which is then passed on to renderResponse, which will then call renderResponseBody and finally the renderPipeline. This block seems to be the place where the actual status code from an ActionResult is actually set. However, the after function is already called (it was called in actionResult, before executeRoutes returns). So what you get is exactly your behavior: when you don't use halt, the correct response status is only set in the actual response but not your logging call.
You've probably tried this, but the quick fix to your InternalServerError not generating the correct HTTP status code when logged is to simply wrap it in another halt call.
As to whether this is a bug, I can't say. I'm guessing probably not, because they did say in the executeRoutes documentation that after is called before the actionResult is passed to renderResponse. What was not clear was that the act of rendering actionResult also sets the HTTP error code, which you wanted to log before.
You'll have to confirm with them on that :).

RxSwift - Fetch undetermined resources via HTTP

I have undetermined resources that need to be fetched from a server. I tried to accomplish this by using the repeatElement() and concat() operators like this:
repeatElement(0, CurrentThreadScheduler.instance).map({ _ -> Observable<[Task]> in
// API.getTasks() uses Alamofire to request data
return API.getTasks(loggedUser, after: loggedUser.taskPullTime)
}).concat().takeWhile({ (tasks) -> Bool in
return tasks.count > 0
})
Unfortunately, repeatElement will just emit an item without waiting for the old one to be handled. I think the reason is that Alamorfire executes in a private serial queue.
However, I cannot figure out how to solve this problem.
I used the strategy inspired from here in my Android project. Everything works fine because Retrofit init HTTP request in a synchronous manner.