What does mono.onErrorResume(Mono:error) do? - project-reactor

I'm working a new project and the codebase is filled with statements like this one:
someFunctionThatReturnsAMono().onErrorResume(Mono::error)...
Where the function's prototype could be:
public Mono<Data> someFunctionThatReturnsAMono()
What does this onErrorResume(Mono::error) do ? No one could explain, and my understanding is that onErrorResume is only called when we already have a Mono::error, so the statement would be in fact useless.
Link to the projectreactor's onErrorResume doc.

It adds nothing (except another step on the schedular), it just unwraps and rewraps the throwable from/to a Error signal.
Note that it does nothing to the throwable itself, so it wont have a "cause" or anything like that.
#Test
public void rethrow() {
StepVerifier.create(Mono.just("hi")
.handle((it, sink) -> sink.error(new RuntimeException(it)))
.log("sink")
.onErrorResume(it -> Mono.error(it))
.log("resume"))
.expectSubscription()
.expectError(RuntimeException.class)
.verify();
}
equivalent imperitive code would look something like:
try{
throw new RuntimeException();
}catch (RuntimeException ex){
throw ex;
}
you could read more on this at: https://projectreactor.io/docs/core/release/reference/#which.errors

Related

MVC Return view from another method

i am unable to end response in case of some condition
eg below (in Upload Action Method), if Logerror method invoked i just want to return view(browser) without further action. i.e return from Upload Action Method.
Plase find modified question what i am trying to achive,
In case of error i want to return view by stopping all further opeartion
public ActionResult Index()
{
return View();
}
public ActionResult Upload()
{
int i=1;
DoSomethingFirst();
//if LogError i dont want execute code below, rather it should end responce
//should not reach here
string s="This should not be executed in case of LogError()";
return View("Index");
}
public void DoSomethingFirst()
{
try{
DoSomethingSecond();
}
catch(exception ex)
{
LogError();
}
}
public void DoSomethingSecond()
{
try{
DoSomethingThird();
}
catch(exception ex)
{
LogError();
}
}
public void DoSomethingThird()
{
try{
DoSomethingother();
}
catch(exception ex)
{
LogError();
}
}
private LogError()
{
Viewbag.Error="Error details";
return View("Index");
}
This doesn't return a result from the current method:
DoSomething();
But this does:
return DoSomething();
If you want to end execution of the current method, you need to do something which exits the method. Basically, either return from the method or throw an exception. Since DoSomething returns a result, presumably you want to return that result. So simply add a return statement when invoking the method.
i tried wit RedirectToAction("Index");
Same issue. You'd need to return the result:
return RedirectToAction("Index");
Edit: Based on your edit to the question, the overall concept still remains. Focusing on this part of your code here:
var s = DoSomethingFirst();
//if true i dont want execute code below, rather it should end responce
//should not reach here
In order to exit the method, any method in C#, you need to either return or throw. So the first question is... Which do you want to do here? If you want to return a redirect, for example, then return a redirect:
return RedirectToAction("SomeAction");
If you want to return the default view, return that:
return View();
If you want to throw an exception:
throw SomeException("Some Message");
The choice is yours. You just need to define:
What you want this method to return or throw under this condition.
How will you know the condition.
For that second point, your code comment says:
//if true ...
Does this mean DoSomethingFirst() returns a bool indicating success or failure? Then that would be a simple if statement:
if (!DoSomethingFirst())
return View();
Another Edit: Based on your comment below:
Inside LogError mehod called by any child method in action method, i want to update view with error message and end the operation without further operation
How will your Update method know that something it invoked internally called LogError()? What information does DoSomethingFirst() return to indicate this fact? Currently it doesn't. Your various DoSomething methods are all swallowing exceptions, which means they are internally handling exceptions so that consuming code doesn't know about them.
If you want consuming code to know about an exception, re-throw that exception. For example:
public void DoSomethingFirst()
{
try
{
DoSomethingSecond();
}
catch(exception ex)
{
LogError();
throw; // <-- this will re-throw ex without modifying it
}
}
This returns information from DoSomethingFirst(), specifically the fact that an error occurred. Your consuming code can then check for that error:
try
{
DoSomethingFirst();
}
catch (Exception ex)
{
// You should *probably* do something with ex too. So far all of your "logging" has been ignoring the actual error.
return View();
}
Regardless of the structure you build, the basics don't change. In order for consuming code to know something about the code it invokes, that invoked code has to expose that information. In order to end execution of a method, you have to either return or throw. Don't hide exceptions from consuming code if you want consuming code to respond to those exceptions.

CodenameOne Connection Request hangs when repeated

I have the following Codename One code for accessing a network resource. It is almost an exact copy of the Codename One tutorial for this use case.
public void executeRequest(){
String url = "http://www.random.net";
InfiniteProgress prog = new InfiniteProgress();
final Dialog dlg = prog.showInifiniteBlocking();
ConnectionRequest r = new ConnectionRequest() {
#Override
protected void postResponse() {
//handle changes to my form
}
#Override
protected void readResponse(InputStream input)
throws IOException {
//handle parsing data
}
#Override
protected void handleIOException(IOException err) {
super.handleIOException(err);
}
};
r.setUrl(url);
r.setPost(false);
r.addArgument("arg", "2");
r.setDuplicateSupported(true);
r.setDisposeOnCompletion(dlg);
NetworkManager.getInstance().addToQueue(r);
}
The first time I run it - no problem. If I try to "refresh" my data by calling the same method over again, the app will hang up with the InfiniteProgress dialog spinning forever. Its almost like the first network request is not ever really completing, and then the second one kind of conflicts. Any ideas what I'm doing wrong?
By default duplicate requests to the exact same URL are disabled, try invoking setDuplicatesSuppotred(true) on the connection request.
For future reference, what fixed this for me was to use
NetworkManager.getInstance().addToQueueAndWait(r);
instead. That cleared up most of my problems.
I stucked with the same problem and none of solutions worked. However, I did it this way:
final NetworkManager nm = NetworkManager.getInstance();
nm.setTimeout(3000);
then
protected void postResponse() {
...
nm.shutdown();
}
and call was made as
nm.addToQueueAndWait(request);
Maybe the fact that NetworkManager was made final did the job, but I put "shutdown" just for sure. It worked for me

Catching Exceptions in the Controller

It seems like if an Exception occurs inside a controller, the view-engine won't go to the intended view, even if the "exception" is caught inside a try-catch block?
or I'm missing something here:
public ActionResult MyController(int? param1, DateTime? param2)
{
MyModel model = new MyModel();
try
{
model = new MyModel();
//AN ERROR HAPPENS HERE (so the code goes to catch the Exception):
model.Connection.Initialize();
}
catch (Exception ex)
{
ViewBag.ErrorMessage = ex.Message;
}
//when I put a break point I get to this following line, however, "MyView" is never displayed!?
return PartialView("MyView", model);
}
You might be getting another exception afterwards, somewhere in your view. Look at the stack trace that displays on the browser page and fix that.

Is there a global handler for async Errors?

In old-fashioned sync code, you can always assure your program won't crash completely by encapsulation your source code to the one big try catch block as in example:
try {
// Some piece of code
} catch (e) {
logger.log(e); // log error
}
However in Dart, when using Futures and Streams, it is not so easy. Following example will crash your application completely
try {
doSomethingAsync().then((result) => throw new Exception());
} catch (e) {
logger.log(e);
}
It doesn't matter that you have code inside the try-catch block.
Yes, you can always use Future.catchError, unfortunately, this won't help you if you are using third-party library function as following:
void someThirdPartyDangerousMethod() {
new Future.value(true).then((result) => throw new Exception());
}
try {
// we can't use catchError, because this method does not return Future
someThirdPartyDangerousMethod();
} catch (e) {
logger.log(e);
}
Is there a way to prevent the untrusty code to break whole your application? Something like global error handler?
You can use the brand new Zones. Just run your code inside the Zone and attach error handler to it.
void someThirdPartyDangerousMethod() {
new Future.value(true).then((result) => throw new Exception());
}
runZoned(() {
// we can't use catchError, because this method does not return Future
someThirdPartyDangerousMethod();
}, onError: (e) {
logger.log(e);
});
This should just work as expected! Every uncatched error will be handled by the onError handler. One thing is different to the classical example with try-catch block. The code running inside the Zone won't stop when error occurs, error is handled by onError callback and the application continues.

How to handle GORM exceptions

I'm trying to implement exception handling for Optimistic lock type exceptions that are thrown by Hibernate but I've encountered a strange issue. It seems I'm unable to catch any Gorm exceptions.
For example I have this code in my service:
try {
User user = User.get(1);
Thread.sleep(10000);
user.viewedAt(new Date());
user.save(flush:true);
} catch (OptimisticLockingException ex) {
log.error("Optimistic lock exception");
} catch (StaleObjectStateException ex) {
log.error("Optimistic lock exception");
}
When I hit this block with two threads, it blows up and the exception propagates to Grails' standard exception handler. The catch blocks are never invoked even though the reported exception is StaleObjectStateException.
I've noticed that I can catch the exception if I let it propagate to the controller and catch it there, but it seems I can't implement exception handling in the service which is weird.
What am I missing?
I got to the bottom of this and I'm posting it in case anyone else runs into this. The issue occurred because the try/catch block was in a transactional service. Although grails reported that the exception was thrown during the save() call, in reality it was called AFTER the entire method, when the transaction was committed.
So it seems that:
flush: true has no effect on transactional services
It's not possible to catch GORM related exceptions in transactional services, at least not without some work
I finally worked around this by manually managing the transaction myself i.e.
try {
User.withNewTransaction {
User user = User.get(id); // Must reload object
.. // do stuff
user.save(flush:true)
}
} catch (OptimisticLockingException ex) {
...
}
I hope this is of use to someone else!
I spent some time working on this problem and have written a more complete solution to handle the case of an optimistic locking exception in Grails.
Firstly, though the exception reported in the stack trace is StaleObjectStateException, the actual exception that gets thrown is HibernateOptimisticLockingFailureException (not "OptimisticLockingException"). Secondly, if you want to generalize this to handle arbitrary closures which modify domain objects, you need to rethrow exceptions thrown inside the closure.
The following static function will take an object and a closure that operates on the object, save it, and if it fails, retry again until it succeeds:
public static retryUpdate(Object o, Closure c) throws Exception {
def retVal
int retryCount = 0
while (retryCount < 5) {
try {
Model.withTransaction { status ->
retVal = c(status)
o.save()
}
return retVal
} catch (HibernateOptimisticLockingFailureException e) {
log.warn "Stale exception caught saving " + o
if (++retryCount >= 3) { // if retry has failed three times, pause before reloading
Thread.sleep(1000)
}
o.refresh()
} catch (UndeclaredThrowableException e2) {
// rethrow exceptions thrown inside transaction
throw e2.getCause()
}
}
return null
}
Model in this case is any GORM model class, doesn't matter which one. In particular it doesn't matter if it is the class of the passed-in object.
Example of use:
AnotherModelClass object = AnotherModelClass.get(id)
retryUpdate(object) {
object.setField("new value")
}

Resources